標籤:
Sharing a File(共用檔案)
該系列文章是我在學習Google開發人員文檔時結合Google翻譯和自身理解編寫的,希望對學習Android開發的朋友帶來些便利,由於個人翻譯水平有限,所以內容包含原文和譯文,希望瀏覽者結合理解,以免步入我可能錯譯的誤區。在此感謝http://android.xsoftlab.net/提供的鏡像,希望轉載者註明出處http://blog.csdn.net/u014031072/article/details/51596803方便查看最新部落格
Once you have set up your app to share files using content URIs, you can respond to other apps’ requests for those files. One way to respond to these requests is to provide a file selection interface from the server app that other applications can invoke. This approach allows a client application to let users select a file from the server app and then receive the selected file’s content URI.
一旦你已經在你的app中通過content URI設定好檔案分享權限設定後,你就能回應其他app對應的檔案請求了。響應這些請求的一種方式是從服務app提供一個其他app可以請求檔案的選擇介面。這種方法使用戶端app允許使用者選擇伺服器上一項檔案,然後接收所選檔案的content URI。
This lesson shows you how to create a file selection Activity in your app that responds to requests for files.
這節課向你展示了如何在你的app中建立一個檔案選擇的activity來回應檔請求。
Receive File Requests(擷取檔案請求)
To receive requests for files from client apps and respond with a content URI, your app should provide a file selection Activity. Client apps start this Activity by calling startActivityForResult() with an Intent containing the action ACTION_PICK. When the client app calls startActivityForResult(), your app can return a result to the client app, in the form of a content URI for the file the user selected.
從用戶端應用程式接收檔案的請求,響應並返回一個content URI,您的app應提供一個檔案選擇activity。用戶端應用程式通過調用startActivityForResult()方法並傳入一個包含ACTION_PICK的action的Intent來啟動該請求活動。當用戶端應用程式調用startActivityForResult()方法時,您的應用程式可以以使用者選擇的檔案內容URI的形式,將結果返回給用戶端應用程式。
To learn how to implement a request for a file in a client app, see the lesson Requesting a Shared File.
學習如何在用戶端app中實現一個檔案請求,請參考Requesting a Shared File課程。
Create a File Selection Activity(建立一個檔案選擇的activity)
To set up the file selection Activity, start by specifying the Activity in your manifest, along with an intent filter that matches the action ACTION_PICK and the categories CATEGORY_DEFAULT and CATEGORY_OPENABLE. Also add MIME type filters for the files your app serves to other apps. The following snippet shows you how to specify the new Activity and intent filter:
要建立一個檔案選擇的activity,先在你的資訊清單檔中定義一個activity,包含一個匹配ACTION_PICK的action的intent filter,它的categories值為CATEGORY_DEFAULT和CATEGORY_OPENABLE。同時添加一個你的app為其他app服務的MIME類型過濾器。下面的代碼片展示了如何定義新的activity和它的intent filter:
<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>
Define the file selection Activity in code(在代碼中定義檔案選擇的activity)
Next, define an Activity subclass that displays the files available from your app’s files/images/ directory in internal storage and allows the user to pick the desired file. The following snippet demonstrates how to define this Activity and respond to the user’s selection:
下一步,定義一個activity子類來顯示你的app內部儲存中files/images/路徑下可用的檔案並允許使用者選擇期望的檔案。下面的代碼片示範了如何定義這個activity並響應使用者的選擇:
public class MainActivity extends Activity { // The path to the root of this app‘s internal storage //app的內部儲存根路徑 private File mPrivateRootDir; // The path to the "images" subdirectory //images子路徑 private File mImagesDir; // Array of files in the images subdirectory //images子路徑下的檔案清單 File[] mImageFiles; // Array of filenames corresponding to mImageFiles // iamges檔案清單中對應的檔案名稱列表 String[] mImageFilenames; // Initialize the Activity //初始化activity @Override protected void onCreate(Bundle savedInstanceState) { ... // Set up an Intent to send back to apps that request a file //定義一個intent來送回給發出檔案請求的app mResultIntent = new Intent("com.example.myapp.ACTION_RETURN_FILE"); // Get the files/ subdirectory of internal storage //擷取記憶體中files/路徑的子路徑 mPrivateRootDir = getFilesDir(); // Get the files/images subdirectory; //擷取files/images路徑的子路徑 mImagesDir = new File(mPrivateRootDir, "images"); // Get the files in the images subdirectory //擷取images子路徑下的檔案清單 mImageFiles = mImagesDir.listFiles(); // Set the Activity‘s result to null to begin with //設定activity的返回結果為null 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 */ ... } ...}
Respond to a File Selection(回應檔選擇介面)
Once a user selects a shared file, your application must determine what file was selected and then generate a content URI for the file. Since the Activity displays the list of available files in a ListView, when the user clicks a file name the system calls the method onItemClick(), in which you can get the selected file.
一旦使用者選擇了一項共用檔案,你的應用必須決定哪個檔案被選擇瞭然後產生該檔案的content URI。因為activity在listview中顯示可用的檔案清單,當使用者點擊檔案名稱時,系統調用listview的onItemClick()方法,在這個方法中你可以擷取到被選擇的檔案。
In onItemClick(), get a File object for the file name of the selected file and pass it as an argument to getUriForFile(), along with the authority that you specified in the <?(去掉問號)provider> element for the FileProvider. The resulting content URI contains the authority, a path segment corresponding to the file’s directory (as specified in the XML meta-data), and the name of the file including its extension. How FileProvider maps directories to path segments based on XML meta-data is described in the section Specify Sharable Directories.
在onItemClick()中,擷取一個對應檔案名稱的檔案對象,和在FileProvider相關的<?(去掉問號)provider>要素中定義好的許可權一起,作為參數傳遞給getUriForFile()方法。得到的結果content URI包含許可權、對應於該檔案的目錄(如在XML中指定)的路徑段和檔案包含其副檔名的檔案名稱。FileProvider 如何映射路徑片段的檔案路徑,基於Specify Sharable Directories章節中關於xml meta-data的描述
The following snippet shows you how to detect the selected file and get a content URI for it:
下面的代碼片展示了如何檢測被選中的檔案並獲得一個對應其的content URI:
protected void onCreate(Bundle savedInstanceState) { ... // Define a listener that responds to clicks on a file in the ListView //定義一個監聽器來響應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 */ //當listview中的一個檔案名稱被點擊後,擷取它的content URI並把它發送給請求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. */ //擷取一個被選中檔案名稱對應的檔案,假設檔案名稱在mImageFilename數組中 File requestFile = new File(mImageFilename[position]); /* * Most file-related method calls need to be in * try-catch blocks. */ //大部分檔案相關的方法調用時需要在try-catch塊中進行 // Use the FileProvider to get a content URI //使用FileProvider來擷取一個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); } ... } }); ... }
Remember that you can only generate content URIs for files that reside in a directory you’ve specified in the meta-data file that contains the <?(去掉問號)paths> element, as described in the section Specify Sharable Directories. If you call getUriForFile() for a File in a path that you haven’t specified, you receive an IllegalArgumentException.
記住,你只能產生在meta-data檔案中包括的<?(去掉問號)paths>要素中定義好的檔案路徑(在Specify Sharable Directories章節中描述的那樣)對應的檔案的content URI。如果你為一個沒有定義好的檔案調用getUriForFile()方法,你將會收到一個IllegalArgumentException異常。
Grant Permissions for the File(為檔案授權)
Now that you have a content URI for the file you want to share with another app, you need to allow the client app to access the file. To allow access, grant permissions to the client app by adding the content URI to an Intent and then setting permission flags on the Intent. The permissions you grant are temporary and expire automatically when the receiving app’s task stack is finished.
現在你已經獲得了一個你想共用給其他app的檔案的content URI,你需要允許用戶端app進入檔案。為了進入檔案,通過添加content URI到一個intent然後設定許可權標籤給該intent來給用戶端app授權。你所授的許可權時暫時併當接收app的堆棧任務完成後可以自動取消的。
The following code snippet shows you how to set read permission for the file:
下面的代碼片展示了如何設定檔案的讀取許可權:
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 //給content URI設定暫時讀取許可權 mResultIntent.addFlags( Intent.FLAG_GRANT_READ_URI_PERMISSION); } ... } ... }); ... }
Caution: Calling setFlags() is the only way to securely grant access to your files using temporary access permissions. Avoid calling Context.grantUriPermission() method for a file’s content URI, since this method grants access that you can only revoke by calling Context.revokeUriPermission().
注意:調用setFlags()方法是使用暫時進入許可權授予你的檔案進入許可權唯一安全的方法。避免為檔案的content URI調用Context.grantUriPermission()方法,因為這個方法擷取的許可權只能通過調用Context.revokeUriPermission()方法來取消許可權。
Share the File with the Requesting App(向請求app共用檔案)
To share the file with the app that requested it, pass the Intent containing the content URI and permissions to setResult(). When the Activity you have just defined is finished, the system sends the Intent containing the content URI to the client app. The following code snippet shows you how to do this:
要向請求檔案的app共用檔案,需要傳遞包含content URI和許可權的intent到setResult()方法。當你定義完這些操作所處的activity銷毀後,系統發送包含content URI的intent到用戶端app。下面的代碼片展示了如何去實現:
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); } } });
Provide users with an way to return immediately to the client app once they have chosen a file. One way to do this is to provide a checkmark or Done button. Associate a method with the button using the button’s android:onClick attribute. In the method, call finish(). For example:
一旦使用者已經選擇好了一個檔案,就向他們提供一個方法立即返回到用戶端app。一個方法是提供一個標誌或完成按鈕。通過使用按鈕的android:onClick屬性關聯一個方法給按鈕。在方法中調用finish()方法。例如:
public void onDoneClick(View v) { // Associate a method with the Done button finish(); }
Google Android開發人員文檔系列-建立有內容分享特性的應用之共用檔案