通过对Google官方的Android Training课程的学习,自己实现的一个小例子,在此分享,谢谢指正。
这个小例子通过使用FileProvider实现文件的跨应用共享,分为服务端APP和客户端APP,以下将进行分别描述。
服务端
- 指定FileProvider
在manifest.xml文件中通过<provider>标签来指定FileProvider
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.sharefile.FileSelectActivity"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
- 指定共享的目录
在res/xml/file_paths.xml中定义FileProvider分享的文件目录
<?xml version="1.0" encoding="utf-8"?>
<resources>
<paths>
<files-path path="images/" name="myimages" />
</paths>
</resources>
<paths>可以有多个子标签:
* files-path:分享内部存储中的目录,和Context.getFilesDir()获取的目录相同
* cache-path:分享内部存储中的cache子目录,和getCacheDir()获取的目录相同
* external-path:分享外部存储根目录中的文件,和Environment.getExternalStorageDirectory()获取的目录相同
* external-files-path:获取外部存储中的app区域,Context#getExternalFilesDir(String) Context.getExternalFilesDir(null)方法可获取相同的目录
- 创建一个文件选择的Activity
在服务端APP上创建一个用于在其他APP请求文件时提供文件选择功能的Activity
- 在manifest.xml文件中定义相应action和category使Activity能够相应文件请求
<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>
- 创建FileSelectActivity
* 初始化Activity
//内部文件数组
private File[] mIntFiles;
private String[] mIntFilenames;
//文件列表
private ListView mFileList;
//adapter
private ArrayAdapter<String> adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.select_files);
init();
setResult(Activity.RESULT_CANCELED, null);
}
private void init() {
mFileList = (ListView) findViewById(R.id.file_list);
//加载文件到数组
loadFiles();
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mIntFilenames);
mFileList.setAdapter(adapter);
mFileList.setOnItemClickListener(this);
}
/*扫描两个files目录的文件,到数组中*/
private void loadFiles() {
String sharedFileDir = "images";
File intFileDir = new File(getFilesDir(), sharedFileDir);
mIntFiles = intFileDir.listFiles();
mIntFilenames = intFileDir.list();
}
* 处理请求的点击事件
```java
/*当条目被点击时,设置setResult,将选择的结果返回给调用此activity的activity*/
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
File requestFile = mIntFiles[position];
Uri fileUri;
String authority = "com.example.guotao.sharefile.FileSelectActivity";
try {
fileUri = FileProvider.getUriForFile(this, authority, requestFile);
Intent resultIntent = new Intent("com.example.guotao.sharefile.ACTION_RETURN_FILE");
if (fileUri != null) {
resultIntent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
resultIntent.setDataAndType(fileUri, getContentResolver().getType(fileUri));
setResult(RESULT_OK, resultIntent);
finish();
} else {
resultIntent.setDataAndType(null, "");
setResult(RESULT_CANCELED, resultIntent);
finish();
}
} catch (Exception e) {
e.printStackTrace();
}
}
1. 通过FileProvider.getUriForFile()方法来获取文件的内容URI
```java
fileUri = FileProvider.getUriForFile(this, authority, requestFile);
<div class="se-preview-section-delimiter"></div>
- 授予其他应用对文件的临时访问权限
resultIntent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
<div class="se-preview-section-delimiter"></div>
客户端
客户端主要是向服务端发送文件请求和处理服务端返回的文件
- 发送文件请求
private Intent mRequestIntent;
// private ParcelFileDescriptor mInputFDP;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRequestIntent = new Intent(Intent.ACTION_PICK);
mRequestIntent.setType("image/jpg");
final Button request_file = (Button) findViewById(R.id.request_file);
request_file.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
requestFile();
}
});
}
protected void requestFile() {
startActivityForResult(mRequestIntent, 0);
}
<div class="se-preview-section-delimiter"></div>
- 处理返回的文件,需要重写onActivityResult()方法
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != RESULT_OK) {
return;
} else {
//Get the file's content uri from incoming intent
Uri returnUri = data.getData();
Cursor returnCursor = getContentResolver().query(returnUri, null, null, null, null);
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
TextView nameView = (TextView) findViewById(R.id.file_name);
TextView sizeView = (TextView) findViewById(R.id.file_size);
nameView.setText(returnCursor.getString(nameIndex));
sizeView.setText(Long.toString(returnCursor.getLong(sizeIndex)));
}
}
源码下载
* 处理返回的文件,需要重写onActivityResult()方法
```java
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != RESULT_OK) {
return;
} else {
//Get the file's content uri from incoming intent
Uri returnUri = data.getData();
Cursor returnCursor = getContentResolver().query(returnUri, null, null, null, null);
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
TextView nameView = (TextView) findViewById(R.id.file_name);
TextView sizeView = (TextView) findViewById(R.id.file_size);
nameView.setText(returnCursor.getString(nameIndex));
sizeView.setText(Long.toString(returnCursor.getLong(sizeIndex)));
}
}