Android官方开发文档Training系列课程中文版:分享文件之分享一个文件
原文地址: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_DEFAULT和CATEGORY_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 storageprivate File mPrivateRootDir;// The path to the "images" subdirectoryprivate File mImagesDir;// Array of files in the images subdirectoryFile[] mImageFiles;// Array of filenames corresponding to mImageFilesString[] mImageFilenames;// Initialize the Activity@Overrideprotected void onCreate(Bundle savedInstanceState) {...// Set up an Intent to send back to apps that request a filemResultIntent =new Intent("com.example.myapp.ACTION_RETURN_FILE");// Get the files/ subdirectory of internal storagemPrivateRootDir = getFilesDir();// Get the files/images subdirectory;mImagesDir = new File(mPrivateRootDir, "images");// Get the files in the images subdirectorymImageFiles = mImagesDir.listFiles();// Set the Activity's result to null to begin withsetResult(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 ListViewmFileListView.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 URItry {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 ListViewmFileListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> adapterView,View view,int position,long rowId) {...if (fileUri != null) {// Grant temporary read permission to the content URImResultIntent.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 ListViewmFileListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> adapterView,View view,int position,long rowId) {...if (fileUri != null) {...// Put the Uri and MIME type in the result IntentmResultIntent.setDataAndType(fileUri,getContentResolver().getType(fileUri));// Set the resultMainActivity.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 buttonfinish();}總結
以上是生活随笔為你收集整理的Android官方开发文档Training系列课程中文版:分享文件之分享一个文件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java】Object类、Object
- 下一篇: Android官方开发文档Trainin