一旦我们设置我们App使用content URI 共享文件,我们可以响应其他App请求这些文件了。其中一个响应这些请求的方式就是从其他应用程序可以调用的服务端App提供一个文件选择器接口。这种方式允许一个客户端应用程序让用户从服务端App选择一个文件,并且接收这个选择文件的content URI。
接收文件请求
为了接收其他客户端App文件请求和响应一个content URI ,我们的App需要提供一个文件选择Activity。客户端App通过调用带有ACTION_PICK action的Intent参数的 startActivityForResult()方法
启动我们的Activity。当客户端调用 startActivityForResult()
创建一个文件选择Activity
为了设置文件选择Activity,在manifest中启动特定的Activity,要带有一个Intent Filter 匹配 action ACTION_PICK
和categories CATEGORY_DEFAULT
和CATEGORY_OPENABLE
. 也要添加MIME类型过滤文件。例如:
<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
例子:
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
*/
...
}
...
}
响应一个文件选择器
一旦我们的用户选择一个共享文件,我们的app必须决定被选择的文件并且产生一个文件的content URI。因为Activity在一个ListVie中展示可分享的文件列表,当用户点击的时候会调用onItemClick()的方法,我们就可以知道文件名字了。
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);
}
...
}
});
...
}
同意文件权限
当接收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);
}
...
}
...
});
...
}
注意!!!调用setFlags()是唯一安全方式使用临时访问权限安全同意访问我们文件。避免调用
Context.grantUriPermission() 方法得到一个文件 content URL,因为这个方法只能通过调用 Context.revokeUriPermission()方法来访问我们的文件。
给请求的App分享文件
传递有content URI的Intent给setResult()方法。例如:
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);
}
}
});
最后要记得finish()我们的App。(在一个Button 之类的finished掉就行了)
public void onDoneClick(View v) {
// Associate a method with the Done button
finish();
}