注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好。

原文链接:http://developer.android.com/training/secure-file-sharing/share-file.html


一旦你配置了你的应用来使用URI共享文件,你可以响应其他应用关于这些文件的需求。一种响应的方法是在服务应用端提供一个文件选择接口,它可以由其他应用激活。这种方法可以允许客户应用端让用户从服务应用端选择一个文件,然后接收这个文件的URI。

这节课将会向你展示如何在你的应用中创建一个用来选择文件的Activity,来响应这些索取文件的需求。


一). 接收文件需求

为了从客户应用端接收一个文件索取需求,然后以URI形式进行响应,你的应用应该提供一个选择文件的Activity。客户应用端通过调用startActivityForResult()来启动这个Activity。该方法包含了一个Intent,它具有ACTION_PICK行为。当客户应用端调用了startActivityForResult(),你的应用可以向客户应用端返回一个结果,该结果即用户所选文件对应的URI。

学习如何在客户应用端实现文件索取需求,阅读:Requesting a Shared File


二). 创建一个文件选择Activity

为了配置文件选择Activity,我们从在清单文件定义你的Activity开始,在其intent过滤器中,匹配ACTION_PICK行为,以及CATEGORY_DEFAULTCATEGORY_OPENABLE类型。另外,为你的应用向其他应用所提供的文件设置MIME类型过滤器。下面的这段代码展示了如何在清单文件中定义新的Activity和intent过滤器:

  1. <manifest xmlns:android="http://schemas.android.com/apk/res/android">
  2. ...
  3. <application>
  4. ...
  5. <activity
  6. android:name=".FileSelectActivity"
  7. android:label="@"File Selector" >
  8. <intent-filter>
  9. <action
  10. android:name="android.intent.action.PICK"/>
  11. <category
  12. android:name="android.intent.category.DEFAULT"/>
  13. <category
  14. android:name="android.intent.category.OPENABLE"/>
  15. <data android:mimeType="text/plain"/>
  16. <data android:mimeType="image/*"/>
  17. </intent-filter>
  18. </activity>

在代码中定义文件选择Activity

下面,定义一个Activity子类它显示在你内部存储的“files/images/”目录下可以获得的文件,然后允许用户选择期望的文件。下面的代码显示了如何定义这个Activity。并且响应用户的选择:

  1. public class MainActivity extends Activity {
  2. // The path to the root of this app's internal storage
  3. private File mPrivateRootDir;
  4. // The path to the "images" subdirectory
  5. private File mImagesDir;
  6. // Array of files in the images subdirectory
  7. File[] mImageFiles;
  8. // Array of filenames corresponding to mImageFiles
  9. String[] mImageFilenames;
  10. // Initialize the Activity
  11. @Override
  12. protected void onCreate(Bundle savedInstanceState) {
  13. ...
  14. // Set up an Intent to send back to apps that request a file
  15. mResultIntent =
  16. new Intent("com.example.myapp.ACTION_RETURN_FILE");
  17. // Get the files/ subdirectory of internal storage
  18. mPrivateRootDir = getFilesDir();
  19. // Get the files/images subdirectory;
  20. mImagesDir = new File(mPrivateRootDir, "images");
  21. // Get the files in the images subdirectory
  22. mImageFiles = mImagesDir.listFiles();
  23. // Set the Activity's result to null to begin with
  24. setResult(Activity.RESULT_CANCELED, null);
  25. /*
  26. * Display the file names in the ListView mFileListView.
  27. * Back the ListView with the array mImageFilenames, which
  28. * you can create by iterating through mImageFiles and
  29. * calling File.getAbsolutePath() for each File
  30. */
  31. ...
  32. }
  33. ...
  34. }

三). 响应一个文件选择

一旦一个用户选择了一个共享的文件,你的应用必须明确哪个文件被选择了,然后为这个文件生成一个对应的URI。若ActivityListView中显示了可获得文件的清单,当用户点击了一个文件名时,系统调用了方法onItemClick(),在该方法中你可以获取被选择的文件。

onItemClick()中,为选择的文件文件名获取一个File对象,然后将它作为参数传递给getUriForFile(),另外还需传入的参数是你为FileProvider所指定的<provider>标签值。这个结果URI包含了相应的被访问权限,一个对应于文件目录的路径标记(如在XML meta-date中定义的),以及包含扩展名的文件名。有关FileProvider如何了解基于XML meta-data的目录路径的信息,可以阅读:Specify Sharable Directories

下面的例子展示了你如何检测选中的文件并且获得一个URI:

  1. protected void onCreate(Bundle savedInstanceState) {
  2. ...
  3. // Define a listener that responds to clicks on a file in the ListView
  4. mFileListView.setOnItemClickListener(
  5. new AdapterView.OnItemClickListener() {
  6. @Override
  7. /*
  8. * When a filename in the ListView is clicked, get its
  9. * content URI and send it to the requesting app
  10. */
  11. public void onItemClick(AdapterView<?> adapterView,
  12. View view,
  13. int position,
  14. long rowId) {
  15. /*
  16. * Get a File for the selected file name.
  17. * Assume that the file names are in the
  18. * mImageFilename array.
  19. */
  20. File requestFile = new File(mImageFilename[position]);
  21. /*
  22. * Most file-related method calls need to be in
  23. * try-catch blocks.
  24. */
  25. // Use the FileProvider to get a content URI
  26. try {
  27. fileUri = FileProvider.getUriForFile(
  28. MainActivity.this,
  29. "com.example.myapp.fileprovider",
  30. requestFile);
  31. } catch (IllegalArgumentException e) {
  32. Log.e("File Selector",
  33. "The selected file can't be shared: " +
  34. clickedFilename);
  35. }
  36. ...
  37. }
  38. });
  39. ...
  40. } 

记住,你能生成的那些URI所对应的文件,是那些在meta-data文件中包含<paths>标签的(即你定义的)目录内的文件,这方面知识在Specify Sharable Directories(博客链接:http://www.cnblogs.com/jdneo/p/3480405.html)中已经讨论过。如果你为一个在你没有指定的目录内的文件调用了getUriForFile()方法,你会收到一个IllegalArgumentException


三). 为文件授权

现在你有了你想要共享给其他应用的文件URI,你需要允许客户应用端访问这个文件。为了允许访问,可以通过将URI添加至一个Intent,然后为该Intent设置权限标记。你所授予的权限是临时的,并且当接收应用的任务栈被完成后,会自动过期。

下面的例子展示了如何为文件设置读权限:

  1. protected void onCreate(Bundle savedInstanceState) {
  2. ...
  3. // Define a listener that responds to clicks in the ListView
  4. mFileListView.setOnItemClickListener(
  5. new AdapterView.OnItemClickListener() {
  6. @Override
  7. public void onItemClick(AdapterView<?> adapterView,
  8. View view,
  9. int position,
  10. long rowId) {
  11. ...
  12. if (fileUri != null) {
  13. // Grant temporary read permission to the content URI
  14. mResultIntent.addFlags(
  15. Intent.FLAG_GRANT_READ_URI_PERMISSION);
  16. }
  17. ...
  18. }
  19. ...
  20. });
  21. ...
  22. }

Caution:

调用setFlags()是唯一安全的方法,为你的文件授予临时的被访问权限。避免对文件URI调用Context.grantUriPermission(),因为通过该方法授予的权限,你只能通过调用Context.revokeUriPermission()来撤销。


四). 与需求应用共享文件

为了与需求应用共享其需要的文件,将包含了URI和响应权限的Intent传递给setResult()。当你定义的Activity被结束后,系统会把这个包含了URI的Intent传递给客户端应用。下面的例子展示了你应该如何做:

  1. protected void onCreate(Bundle savedInstanceState) {
  2. ...
  3. // Define a listener that responds to clicks on a file in the ListView
  4. mFileListView.setOnItemClickListener(
  5. new AdapterView.OnItemClickListener() {
  6. @Override
  7. public void onItemClick(AdapterView<?> adapterView,
  8. View view,
  9. int position,
  10. long rowId) {
  11. ...
  12. if (fileUri != null) {
  13. ...
  14. // Put the Uri and MIME type in the result Intent
  15. mResultIntent.setDataAndType(
  16. fileUri,
  17. getContentResolver().getType(fileUri));
  18. // Set the result
  19. MainActivity.this.setResult(Activity.RESULT_OK,
  20. mResultIntent);
  21. } else {
  22. mResultIntent.setDataAndType(null, "");
  23. MainActivity.this.setResult(RESULT_CANCELED,
  24. mResultIntent);
  25. }
  26. }
  27. }); 

向用户提供一个一旦他们选择了文件就能立即回到客户应用的方法。一种实现的方法是提供一个勾选框或者一个完成按钮。使用按钮的android:onClick属性字段为它关联一个方法。在该方法中,调用finish()。例如:

  1. public void onDoneClick(View v) {
  2. // Associate a method with the Done button
  3. finish();
  4. }

【Android Developers Training】 37. 共享一个文件的更多相关文章

  1. 【Android Developers Training】 25. 保存文件

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  2. 【Android Developers Training】 39. 获取文件信息

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  3. 【Android Developers Training】 35. 序言:分享文件

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  4. 【Android Developers Training】 23. 序言:保存数据

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  5. 【Android Developers Training】 95. 创建一个同步适配器

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  6. 【Android Developers Training】 4. 启动另一个Activity

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  7. 【Android Developers Training】 3. 构建一个简单UI

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  8. 【Android Developers Training】 1. 创建一个Android项目工程

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  9. 【Android Developers Training】 105. 显示一个位置地址

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

随机推荐

  1. Linux(ubuntu)下jdk&tomcat的安装

    1.下载相应版本的jdk及tomcat:sudo wget ${url} 2.解压: tar zxvf jdk-7u79-linux-x64.tar.gz​ tar zxvf apache-tomca ...

  2. TCP三次握手(建立连接)/四次挥手(关闭连接)

    TCP数据包格式 顺序号(32位):用来标识从TCP源端向TCP目的端发送的数据字节流,它表示在这个报文段中的第一个数据字节的顺序号.如果将字节流看作在两个应用程序间的单向流动,则TCP用顺序号对每个 ...

  3. 自己实现so加载器

    在进行安全研究中,我们需要经常使用ida等工具对app的so进行动态调试.这其中遇到的最大问题可能就是app加了反调试.反root等保护手段对应用运行环境进行检测,而这些手段往往是在我们附加进程之前就 ...

  4. Ubuntu安装Cassandra

    Uninstall Cassandra $ sudo su remove cassandra $ apt-get remove cassandra cleaned the cassandra fold ...

  5. 《安卓网络编程》之第一篇 java环境下模拟客户端、服务器端

    1.Socket简介 在网络上的两个程序通过一个双向的通信连接实现数据的交换,这个双向链路的一端称为一个Socket.Socket通常用来实现客户方和服务方的连接.Socket是TCP/IP协议的一个 ...

  6. 树莓派安装FLASK服务;并在端网页读取 GPIO状态和系统时间

    做过一些物联网的作品:因为不想一直做APP来控制,因为不能每个人都去下载你自己做的APP,浏览器大家都是有的:那么每个人通过浏览器WEB来访问我们服务器,岂不是很简单和方便,采用flask+pytho ...

  7. Java项目和maven项目中如何获取&设置配置文件中的属性

    通常情况下,我们会在一些配置文件文件中配置一些属性.如: indexPath = E\:\\Tomcat_7.0\\webapps\\ipost_stage\\lucene\\index imgUpl ...

  8. 多线程编程-- part 3 多线程同步->synchronized关键字

    多线程同时访问一个资源,可以会产生不可预料的结果,所以为这个资源加锁,访问资源的第一个线程为其加锁后,其他线程便不能在使用那个资源,直到锁被解除. 举个例子: 存款1000元,能取出800的时候我就取 ...

  9. Mac下安装第三方模块报错:‘sqlfront.h‘ file not found的解决办法

    1.软件环境: mac环境:10.11.6(15G31) python: 3.6 2.问题: sudo pip install pymssql 后出现下面问题: fatal error: 'sqlfr ...

  10. SVN版本控制系统搭建(+结合http服务)

    .zise { background: #CCCCFF; color: white; text-align: center } .fense { color: #FFCCCC; text-align: ...