【Android Developers Training】 37. 共享一个文件
注:本文翻译自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_DEFAULT和CATEGORY_OPENABLE类型。另外,为你的应用向其他应用所提供的文件设置MIME类型过滤器。下面的这段代码展示了如何在清单文件中定义新的Activity和intent过滤器:
<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
下面,定义一个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(),另外还需传入的参数是你为FileProvider所指定的<provider>标签值。这个结果URI包含了相应的被访问权限,一个对应于文件目录的路径标记(如在XML meta-date中定义的),以及包含扩展名的文件名。有关FileProvider如何了解基于XML 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);
}
...
}
});
...
}
记住,你能生成的那些URI所对应的文件,是那些在meta-data文件中包含<paths>标签的(即你定义的)目录内的文件,这方面知识在Specify Sharable Directories(博客链接:http://www.cnblogs.com/jdneo/p/3480405.html)中已经讨论过。如果你为一个在你没有指定的目录内的文件调用了getUriForFile()方法,你会收到一个IllegalArgumentException。
三). 为文件授权
现在你有了你想要共享给其他应用的文件URI,你需要允许客户应用端访问这个文件。为了允许访问,可以通过将URI添加至一个Intent,然后为该Intent设置权限标记。你所授予的权限是临时的,并且当接收应用的任务栈被完成后,会自动过期。
下面的例子展示了如何为文件设置读权限:
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()来撤销。
四). 与需求应用共享文件
为了与需求应用共享其需要的文件,将包含了URI和响应权限的Intent传递给setResult()。当你定义的Activity被结束后,系统会把这个包含了URI的Intent传递给客户端应用。下面的例子展示了你应该如何做:
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);
}
}
});
向用户提供一个一旦他们选择了文件就能立即回到客户应用的方法。一种实现的方法是提供一个勾选框或者一个完成按钮。使用按钮的android:onClick属性字段为它关联一个方法。在该方法中,调用finish()。例如:
public void onDoneClick(View v) {
// Associate a method with the Done button
finish();
}
【Android Developers Training】 37. 共享一个文件的更多相关文章
- 【Android Developers Training】 25. 保存文件
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 39. 获取文件信息
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 35. 序言:分享文件
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 23. 序言:保存数据
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 95. 创建一个同步适配器
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 4. 启动另一个Activity
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 3. 构建一个简单UI
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 1. 创建一个Android项目工程
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 105. 显示一个位置地址
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
随机推荐
- 转:MySQL表名不区分大小写
在LINUX下调一个程序老说找不到表,但是我明明是建了表的,在MYSQL的命令行下也可以查到,为什么程序就找不到表呢? 一.linux中mysql大小写详情: 1.数据库名严格区分大小写 2.表名严格 ...
- libsvm参数选择
以前接触过libsvm,现在算在实际的应用中学习 LIBSVM 使用的一般步骤是: 1)按照LIBSVM软件包所要求的格式准备数据集: 2)对数据进行简单的缩放操作: 3)首要考虑选用RBF 核函数: ...
- 在 iOS 10.0 之后, App 要调用手机相机与相簿应注意的事项
iOS 的 SDK 每一年至少都会有一次大改版,从 2009 到 2016 年,版号已经到了第 10 版了,很轻易的就追上了 Mac OSX. 每一次的大改版都会有不少新的功能或新的规范,在 iOS ...
- 主机设置ss代理,虚拟机共享代理
代理的原理: 关于代理的具体的书面定义你百度谷歌可以知道.这里,我想简单通过一个例子,说明代理的原理: 假如,你在北京,但你女朋友在广州,你有东西要给你的女朋友,但是正好你这几天公司有事,所以你不能去 ...
- 在JBoss AS7中进行项目部署
http://developer.51cto.com/art/201111/305178.htm
- R绘图字体解决方案(转)
COS论坛里面经常会遇到的一个问题就是绘图时中文字体怎么解决.最初,一个流行的方法是使用family = "GB1",但一般这样做出来的图比较难看,而且并没有完全解决问题.后来发现 ...
- 观《IT培训行业揭秘》触发北大青鸟回忆
在园子里看到这篇文章<IT培训行业解密(六)>时,挺有感触,回忆顿时涌上心头: 我想起了当年单纯的我们因为各自的原因来到北大青鸟,或因前途迷茫而选择想找一条出路,或因父母的信息闭塞而想给我 ...
- GPU编程--kernels(2)
"如何区分不同的数据单位单位呢?" "如何确定程序是在CPU端执行,还是GPU端执行呢?" "如何确定要调用的GPU线程数呢?" 下面举一个 ...
- iOS CAEmitterLayer 实现粒子发射动画效果
iOS CAEmitterLayer 实现粒子发射动画效果 效果图 代码已上传 GitHub:https://github.com/Silence-GitHub/CoreAnimationDemo 动 ...
- linux 系统备份日志
题目: 备份日志 小明是一个服务器管理员,他需要每天备份论坛数据(这里我们用日志替代),备份当天的日志并删除之前的日志.而且备份之后文件名是年-月-日的格式.alternatives.log在/var ...