注:本文翻譯自Google官方的Android Developers Training文檔,譯者技術(shù)一般,由于喜愛安卓而產(chǎn)生了翻譯的念頭,純屬個人興趣愛好。
原文鏈接: http://developer.android.com/training/secure-file-sharing/share-file.html
一旦你配置了你的應(yīng)用來使用URI共享文件,你可以響應(yīng)其他應(yīng)用關(guān)于這些文件的需求。一種響應(yīng)的方法是在服務(wù)應(yīng)用端提供一個文件選擇接口,它可以由其他應(yīng)用激活。這種方法可以允許客戶應(yīng)用端讓用戶從服務(wù)應(yīng)用端選擇一個文件,然后接收這個文件的URI。
這節(jié)課將會向你展示如何在你的應(yīng)用中創(chuàng)建一個用來選擇文件的 Activity ,來響應(yīng)這些索取文件的需求。
一). 接收文件需求
為了從客戶應(yīng)用端接收一個文件索取需求,然后以URI形式進(jìn)行響應(yīng),你的應(yīng)用應(yīng)該提供一個選擇文件的
Activity
。客戶應(yīng)用端通過調(diào)用
startActivityForResult()
來啟動這個
Activity
。該方法包含了一個
Intent
,它具有
ACTION_PICK
行為。當(dāng)客戶應(yīng)用端調(diào)用了
startActivityForResult()
,你的應(yīng)用可以向客戶應(yīng)用端返回一個結(jié)果,該結(jié)果即用戶所選文件對應(yīng)的URI。
學(xué)習(xí)如何在客戶應(yīng)用端實現(xiàn)文件索取需求,閱讀: Requesting a Shared File 。
二). 創(chuàng)建一個文件選擇Activity
為了配置文件選擇
Activity
,我們從在清單文件定義你的
Activity
開始,在其intent過濾器中,匹配
ACTION_PICK
行為,以及
CATEGORY_DEFAULT
和
CATEGORY_OPENABLE
類型。另外,為你的應(yīng)用向其他應(yīng)用所提供的文件設(shè)置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 子類它顯示在你內(nèi)部存儲的“ files/images/ ”目錄下可以獲得的文件,然后允許用戶選擇期望的文件。下面的代碼顯示了如何定義這個 Activity 。并且響應(yīng)用戶的選擇:
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 */ ... } ... }
三). 響應(yīng)一個文件選擇
一旦一個用戶選擇了一個共享的文件,你的應(yīng)用必須明確哪個文件被選擇了,然后為這個文件生成一個對應(yīng)的URI。若 Activity 在 ListView 中顯示了可獲得文件的清單,當(dāng)用戶點擊了一個文件名時,系統(tǒng)調(diào)用了方法 onItemClick() ,在該方法中你可以獲取被選擇的文件。
在 onItemClick() 中,為選擇的文件文件名獲取一個 File 對象,然后將它作為參數(shù)傳遞給 getUriForFile() ,另外還需傳入的參數(shù)是你為 FileProvider 所指定的 <provider> 標(biāo)簽值。這個結(jié)果URI包含了相應(yīng)的被訪問權(quán)限,一個對應(yīng)于文件目錄的路徑標(biāo)記(如在XML meta-date中定義的),以及包含擴展名的文件名。有關(guān) 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所對應(yīng)的文件,是那些在meta-data文件中包含 <paths>標(biāo)簽的(即你定義的)目錄內(nèi)的文件,這方面知識在 Specify Sharable Directories (博客鏈接: http://www.cnblogs.com/jdneo/p/3480405.html )中已經(jīng)討論過。如果你為一個在你沒有指定的目錄內(nèi)的文件調(diào)用了 getUriForFile() 方法,你會收到一個 IllegalArgumentException 。
三). 為文件授權(quán) ?
現(xiàn)在你有了你想要共享給其他應(yīng)用的文件URI,你需要允許客戶應(yīng)用端訪問這個文件。為了允許訪問,可以通過將URI添加至一個 Intent ,然后為該 Intent 設(shè)置權(quán)限標(biāo)記。你所授予的權(quán)限是臨時的,并且當(dāng)接收應(yīng)用的任務(wù)棧被完成后,會自動過期。
下面的例子展示了如何為文件設(shè)置讀權(quán)限:
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:
調(diào)用 setFlags() 是唯一安全的方法,為你的文件授予臨時的被訪問權(quán)限。避免對文件URI調(diào)用 Context.grantUriPermission() ,因為通過該方法授予的權(quán)限,你只能通過調(diào)用 Context.revokeUriPermission() 來撤銷。
四). 與需求應(yīng)用共享文件
為了與需求應(yīng)用共享其需要的文件,將包含了URI和響應(yīng)權(quán)限的 Intent 傳遞給 setResult() 。當(dāng)你定義的 Activity 被結(jié)束后,系統(tǒng)會把這個包含了URI的 Intent 傳遞給客戶端應(yīng)用。下面的例子展示了你應(yīng)該如何做:
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); } } }); ?
向用戶提供一個一旦他們選擇了文件就能立即回到客戶應(yīng)用的方法。一種實現(xiàn)的方法是提供一個勾選框或者一個 完成 按鈕。使用按鈕的 android:onClick 屬性字段為它關(guān)聯(lián)一個方法。在該方法中,調(diào)用 finish() 。例如:
public void onDoneClick(View v) { // Associate a method with the Done button finish(); }
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
