Android官方开发文档Training系列课程中文版:分享文件之分享一个文件

简介: 原文地址:http://android.xsoftlab.net/training/secure-file-sharing/share-file.html一旦APP设置通过URI的方式共享文件,你需要响应其它APP请求这些文件的请求。

原文地址:http://android.xsoftlab.net/training/secure-file-sharing/share-file.html

一旦APP设置通过URI的方式共享文件,你需要响应其它APP请求这些文件的请求。响应这些请求的一种方式是,在服务端APP上提供一个文件选择接口,以便其它的程序可以调用。这种方法允许客户端程序的用户从服务端选择一个文件,然后接收被选择文件的URI地址。

这节课展示了如何在Activity中创建文件选择功能,以便响应文件请求。

接收文件请求

为了接收客户端APP的文件请求,以及以URI的方式作出响应,APP应该在Activity中提供文件选择器。这样的话,客户端APP可以通过调用startActivityForResult()方法启动这个Activity。当客户端调用了startActivityForResult()方法,你的APP可以返回一个结果给客户端APP,这个结果以URI的形式将用户选择的文件返回。

有关学习如何在客户端APP中实现文件的请求,请参见课程: Requesting a Shared File

创建一个文件选择器Activity

为了设置文件选择器Activity,首选需要在清单文件中指定activity,并在其中附加意图过滤器,这个意图过滤器用来匹配行为ACTION_PICK以及类别CATEGORY_DEFAULTCATEGORY_OPENABLE。还要给服务端给客户端提供的文件添加MIME类型过滤器。下面的代码片段展示了如何指定一个新Activity以及过滤器:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    ...
        <application>
        ...
            <activity
                android:name=".FileSelectActivity"
                android:label="@"File Selector" >
                <intent-filter>
                    <action
                        android:name="android.intent.action.PICK"/>
                    <category
                        android:name="android.intent.category.DEFAULT"/>
                    <category
                        android:name="android.intent.category.OPENABLE"/>
                    <data android:mimeType="text/plain"/>
                    <data android:mimeType="image/*"/>
                </intent-filter>
            </activity>

在代码中定义文件选择器

接下来,定义一个Activity来展示内部存储器中files/images/目录下的可用文件,并允许用户来选择需要的文件。下面这段代码演示了如何定义一个Activity来响应用户的选择:

public class MainActivity extends Activity {
    // The path to the root of this app's internal storage
    private File mPrivateRootDir;
    // The path to the "images" subdirectory
    private File mImagesDir;
    // Array of files in the images subdirectory
    File[] mImageFiles;
    // Array of filenames corresponding to mImageFiles
    String[] mImageFilenames;
    // Initialize the Activity
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        // Set up an Intent to send back to apps that request a file
        mResultIntent =
                new Intent("com.example.myapp.ACTION_RETURN_FILE");
        // Get the files/ subdirectory of internal storage
        mPrivateRootDir = getFilesDir();
        // Get the files/images subdirectory;
        mImagesDir = new File(mPrivateRootDir, "images");
        // Get the files in the images subdirectory
        mImageFiles = mImagesDir.listFiles();
        // Set the Activity's result to null to begin with
        setResult(Activity.RESULT_CANCELED, null);
        /*
         * Display the file names in the ListView mFileListView.
         * Back the ListView with the array mImageFilenames, which
         * you can create by iterating through mImageFiles and
         * calling File.getAbsolutePath() for each File
         */
         ...
    }
    ...
}

响应文件选择器

一旦用户选择了被共享的文件,你的程序必须检查哪一个文件被选中,并且生成该文件的URI地址。前面的部分Activity在ListView中展示了可用的文件列表,当用户点击了文件的名称,随之系统会调用方法onItemClick(),在这个方法中你可以获取到被选中的文件。

onItemClick()方法中,从被选择的文件中获得文件的File对象,然后将这个对象作为参数传递给getUriForFile(),它会伴随着权限一并加入,这个权限是由 < provider>元素指定的。结果URI会包含权限、文件在相应目录中的路径段(在XML meta-data中指定的部分)以及文明的名称和其扩展部分。有关FileProvider如何映射meta-data与路径段的目录,请看章节Specify Sharable Directories

下面的代码段展示了如何检测被选择的文件以及获取该文件的URI:

    protected void onCreate(Bundle savedInstanceState) {
        ...
        // Define a listener that responds to clicks on a file in the ListView
        mFileListView.setOnItemClickListener(
                new AdapterView.OnItemClickListener() {
            @Override
            /*
             * When a filename in the ListView is clicked, get its
             * content URI and send it to the requesting app
             */
            public void onItemClick(AdapterView<?> adapterView,
                    View view,
                    int position,
                    long rowId) {
                /*
                 * Get a File for the selected file name.
                 * Assume that the file names are in the
                 * mImageFilename array.
                 */
                File requestFile = new File(mImageFilename[position]);
                /*
                 * Most file-related method calls need to be in
                 * try-catch blocks.
                 */
                // Use the FileProvider to get a content URI
                try {
                    fileUri = FileProvider.getUriForFile(
                            MainActivity.this,
                            "com.example.myapp.fileprovider",
                            requestFile);
                } catch (IllegalArgumentException e) {
                    Log.e("File Selector",
                          "The selected file can't be shared: " +
                          clickedFilename);
                }
                ...
            }
        });
        ...
    }

要记住,你只可以对在< paths>元素中指定目录下的文件进行URI编码,就像Specify Sharable Directories这节课中描述的一样。如果你对getUriForFile()方法中传入的File参数并没有在< path>元素中指定,那么你会收到一个 IllegalArgumentException异常。

对文件授予权限

现在对将要分享的文件有了一个URI,你需要允许客户端APP来访问这个文件。为了允许访问,需要通过添加URI到一个Intent上,并且在这个Intent上设置权限标志。产生的这个权限是个临时权限,并且会在接收端APP任务结束的时候自动终止。

下面这段代码展示了如何对文件设置读取权限:

    protected void onCreate(Bundle savedInstanceState) {
        ...
        // Define a listener that responds to clicks in the ListView
        mFileListView.setOnItemClickListener(
                new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView,
                    View view,
                    int position,
                    long rowId) {
                ...
                if (fileUri != null) {
                    // Grant temporary read permission to the content URI
                    mResultIntent.addFlags(
                        Intent.FLAG_GRANT_READ_URI_PERMISSION);
                }
                ...
             }
             ...
        });
    ...
    }

Caution:安全的对文件授予临时访问权限,setFlags()是唯一的方式。要避免对文件的URI使用Context.grantUriPermission()方法,因为该方法授予的权限只可以通过Context.revokeUriPermission()方法撤销。

对客户端APP共享文件

如果要共享文件给客户端APP,需要传递一个Intent给setResult(),这个Intent包含了文件的URI以及访问权限。当你定义的这个Activity结束时,系统会发送这个Intent给客户端APP,下面这段代码展示了如何实现这部分功能:

    protected void onCreate(Bundle savedInstanceState) {
        ...
        // Define a listener that responds to clicks on a file in the ListView
        mFileListView.setOnItemClickListener(
                new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView,
                    View view,
                    int position,
                    long rowId) {
                ...
                if (fileUri != null) {
                    ...
                    // Put the Uri and MIME type in the result Intent
                    mResultIntent.setDataAndType(
                            fileUri,
                            getContentResolver().getType(fileUri));
                    // Set the result
                    MainActivity.this.setResult(Activity.RESULT_OK,
                            mResultIntent);
                    } else {
                        mResultIntent.setDataAndType(null, "");
                        MainActivity.this.setResult(RESULT_CANCELED,
                                mResultIntent);
                    }
                }
        });

一旦用户选择了文件,那么就应该立即带用户返回客户端APP。实现这种方式的一种方法就是提供一个钩形符号或者结束按钮。使用Button的android:onClick属性与对应的Button相关联。在方法中。调用finish()方法:

    public void onDoneClick(View v) {
        // Associate a method with the Done button
        finish();
    }
目录
相关文章
|
10月前
|
Android开发 开发者
Android自定义View之不得不知道的文件attrs.xml(自定义属性)
本文详细介绍了如何通过自定义 `attrs.xml` 文件实现 Android 自定义 View 的属性配置。以一个包含 TextView 和 ImageView 的 DemoView 为例,讲解了如何使用自定义属性动态改变文字内容和控制图片显示隐藏。同时,通过设置布尔值和点击事件,实现了图片状态的切换功能。代码中展示了如何在构造函数中解析自定义属性,并通过方法 `setSetting0n` 和 `setbackeguang` 实现功能逻辑的优化与封装。此示例帮助开发者更好地理解自定义 View 的开发流程与 attrs.xml 的实际应用。
284 2
Android自定义View之不得不知道的文件attrs.xml(自定义属性)
|
10月前
|
Java Android开发
Android studio中build.gradle文件简单介绍
本文解析了Android项目中build.gradle文件的作用,包括jcenter仓库配置、模块类型定义、包名设置及依赖管理,涵盖本地、库和远程依赖的区别。
855 19
|
移动开发 安全 Java
Android历史版本与APK文件结构
通过以上内容,您可以全面了解Android的历史版本及其主要特性,同时掌握APK文件的结构和各部分的作用。这些知识对于理解Android应用的开发和发布过程非常重要,也有助于在实际开发中进行高效的应用管理和优化。希望这些内容对您的学习和工作有所帮助。
1442 83
|
10月前
|
存储 XML Java
Android 文件数据储存之内部储存 + 外部储存
简介:本文详细介绍了Android内部存储与外部存储的使用方法及核心原理。内部存储位于手机内存中,默认私有,适合存储SharedPreferences、SQLite数据库等重要数据,应用卸载后数据会被清除。外部存储包括公共文件和私有文件,支持SD卡或内部不可移除存储,需申请权限访问。文章通过代码示例展示了如何保存、读取、追加、删除文件以及将图片保存到系统相册的操作,帮助开发者理解存储机制并实现相关功能。
2480 2
|
Java Android开发 C++
Android Studio JNI 使用模板:c/cpp源文件的集成编译,快速上手
本文提供了一个Android Studio中JNI使用的模板,包括创建C/C++源文件、编辑CMakeLists.txt、编写JNI接口代码、配置build.gradle以及编译生成.so库的详细步骤,以帮助开发者快速上手Android平台的JNI开发和编译过程。
1297 1
|
ARouter Android开发
Android不同module布局文件重名被覆盖
Android不同module布局文件重名被覆盖
|
存储 监控 数据库
Android经典实战之OkDownload的文件分段下载及合成原理
本文介绍了 OkDownload,一个高效的 Android 下载引擎,支持多线程下载、断点续传等功能。文章详细描述了文件分段下载及合成原理,包括任务创建、断点续传、并行下载等步骤,并展示了如何通过多种机制保证下载的稳定性和完整性。
709 1
|
开发工具 git 索引
repo sync 更新源码 android-12.0.0_r34, fatal: 不能重置索引文件至版本 ‘v2.27^0‘。
本文描述了在更新AOSP 12源码时遇到的repo同步错误,并提供了通过手动git pull更新repo工具来解决这一问题的方法。
724 1
|
ARouter Android开发
Android不同module布局文件重名被覆盖
Android不同module布局文件重名被覆盖
1037 0
|
存储 数据库 Android开发
🔥Android Jetpack全解析!拥抱Google官方库,让你的开发之旅更加顺畅无阻!🚀
【7月更文挑战第28天】在Android开发中追求高效稳定的路径?Android Jetpack作为Google官方库集合,是你的理想选择。它包含多个独立又协同工作的库,覆盖UI到安全性等多个领域,旨在减少样板代码,提高开发效率与应用质量。Jetpack核心组件如LiveData、ViewModel、Room等简化了数据绑定、状态保存及数据库操作。引入Jetpack只需在`build.gradle`中添加依赖。例如,使用Room进行数据库操作变得异常简单,从定义实体到实现CRUD操作,一切尽在掌握之中。拥抱Jetpack,提升开发效率,构建高质量应用!
591 4