Android官方开发文档Training系列课程中文版:通过NFC共享文件之从其它设备接收文件
原文地址:http://android.xsoftlab.net/training/beam-files/receive-files.html
Android Beam文件傳輸系統會將文件拷貝到接收設備的指定目錄中。它還會使用Android媒體掃描器掃描被拷貝的文件,并會將媒體文件的入口信息添加到MediaStore提供者中去。
響應展示數據的請求
當Android Beam文件傳輸系統結束了文件拷貝,它會發送通知,這個通知會包含一個Intent對象,這個Intent對象的行為為ACTION_VIEW,以及被傳送的第一個文件的MIME類型,以及指向第一個文件的URI地址。當用戶點擊了通知,這個Intent會被廣播到系統中。為了使APP可以響應這個意圖,需要在清單文件中的響應Activity的< activity>元素下添加元素,并在其中添加如下子元素:
<action android:name="android.intent.action.VIEW" />- 匹配由通知發送來的ACTION_VIEW意圖。
- 匹配沒有明確類別的意圖。
- 匹配一種MIME類型。這里的mime-type類型應為APP可以處理的類型。
舉個例子,下面這段代碼展示了如何在被觸發的Activity com.example.android.nfctransfer.ViewActivity的清單文件中添加意圖過濾器:
<activity android:name="com.example.android.nfctransfer.ViewActivity"android:label="Android Beam Viewer" >...<intent-filter><action android:name="android.intent.action.VIEW"/><category android:name="android.intent.category.DEFAULT"/>...</intent-filter></activity>**Note:**Android Beam文件傳輸系統并不是ACTION_VIEW意圖的唯一來源,接收設備上的其它APP也可以發送含有這個行為的意圖。Get the directory from a content URI這節會討論如何處理這種情況。
請求文件權限
為了可以讀取Android Beam文件傳輸系統拷貝到設備的文件,需要請求READ_EXTERNAL_STORAGE權限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />如果你想要將被拷貝的文件拷貝到自己的存儲器上,這里應該使用權限WRITE_EXTERNAL_STORAGE。WRITE_EXTERNAL_STORAGE權限包含了READ_EXTERNAL_STORAGE權限。
Note:在Android 4.2.2上,READ_EXTERNAL_STORAGE權限會在用戶需要的時候強制執行。未來的版本可能在各種情況下都需要該權限,所以為了確保向后兼容,請在它要求以前就給它添加上。
因為你的APP對其內部存儲器有操作的權利,所以在拷貝文件到內部存儲器上時不需要請求寫入權限。
獲取被拷貝文件的目錄
Android Beam文件傳輸系統會通過一個單一的傳輸通道將所有的文件拷貝到接收設備上一個目錄中。Android Beam文件傳輸系統的通知會將內容Intent中的URI指向到第一個已被傳送的文件上。然而,APP可能還需要對傳輸系統上的其它ACTION_VIEW意圖來源進行接收。為了判斷應該如何處理發送過來的Intent,你需要檢查它的計劃(scheme)與權力(authority)。
為了可以從URI上獲取計劃,需要調用Uri.getScheme()方法。下面這段代碼展示了如何檢查計劃以及如何處理URI的訪問:
public class MainActivity extends Activity {...// A File object containing the path to the transferred filesprivate File mParentPath;// Incoming Intentprivate Intent mIntent;.../** Called from onNewIntent() for a SINGLE_TOP Activity* or onCreate() for a new Activity. For onNewIntent(),* remember to call setIntent() to store the most* current Intent**/private void handleViewIntent() {...// Get the Intent actionmIntent = getIntent();String action = mIntent.getAction();/** For ACTION_VIEW, the Activity is being asked to display data.* Get the URI.*/if (TextUtils.equals(action, Intent.ACTION_VIEW)) {// Get the URI from the IntentUri beamUri = mIntent.getData();/** Test for the type of URI, by getting its scheme value*/if (TextUtils.equals(beamUri.getScheme(), "file")) {mParentPath = handleFileUri(beamUri);} else if (TextUtils.equals(beamUri.getScheme(), "content")) {mParentPath = handleContentUri(beamUri);}}...}... }從文件URI獲取目錄
如果接收到的Intent包含一個文件URI,那么URI會包含文件的絕對文件名,包括全目錄路徑以及文件的名字。對Android Beam文件傳輸系統來說,如果有的話,這個目錄路徑指向了其它被傳送文件的位置。為了獲取目錄路徑,獲取URI的路徑部分,路徑部分包含了除了前綴file:之外的所有URI。從路徑部分創建一個File對象,然后該文件對象的上級目錄:
...public String handleFileUri(Uri beamUri) {// Get the path part of the URIString fileName = beamUri.getPath();// Create a File object for this filenameFile copiedFile = new File(fileName);// Get a string containing the file's parent directoryreturn copiedFile.getParent();}...從內容URI獲取目錄
如果接收到的Intent包含一個內容URI,那這個URI可能會指向在MediaStore內容提供者中存儲的文件的路徑和名稱。你可以通過測試URI的權限值來判斷是否是MediaStore的內容URI。MediaStore的內容URI可能來自Android Beam文件傳輸系統或者其它APP,但是無論什么情況你都可以從內容URI中接收一個目錄以及文件的名稱。
你也可以接收包含了不同于MediaStore的內容URI的ACTION_VIEW意圖。在這種情況下,這內容URI不包含 ACTION_VIEW的權限值,以及內容URI通常不會執行一個目錄。
Note: 對于Android Beam文件傳輸系統來說,你可以接收含有內容URI的ACTION_VIEW意圖,如果第一個接到的文件含有”audio/*”, “image/*”, 或者”video/*”之類的MIME類型。這意味著它是和媒體有關的。Android Beam文件傳輸系統會索引媒體文件,它會通過運行媒體掃描器掃描存儲有被傳送文件的目錄來傳送文件。媒體掃描器會將掃描結果寫入到MediaStore內容提供者中,然后它會傳第一個文件的內容URI給Android Beam文件傳輸系統。這個內容URI是在通知意圖中的接收到的那個。給了獲取第一個文件的目錄,需要使用內容URI從MediaStore中接收它。
判斷內容提供者
為了判斷是否可以從內容URI中接收文件的目錄,通過調用Uri.getAuthority()來獲取URI的權限來判斷與內容提供者相關聯的URI。它的值可能有兩種情況:
MediaStore.AUTHORITY
這個URI是可以被MediaStore追蹤到的單個文件或者多個文件。MediaStore中可以接收全路徑名稱,以及可以從文件名中獲取它的目錄。
其它任意的權限值
從其它內容提供者而來的內容URI。展示了與內容URI相關的數據,但是不能夠獲取文件的目錄。
為了可以從MediaStore內容URI中獲取文件目錄,需要進行查詢,查詢需要指定Uri參數為接收到的內容URI,projection參數為列MediaColumns.DATA,它返回的Cursor對象包含了URI所代表的文件的全路徑名稱。這個路徑還包含Android Beam文件傳輸系統剛剛拷貝到設備上的其它所有文件。
下面這段代碼展示了如何測試內容URI的權限以及從被傳送的文件中接收路徑以及文件名:
...public String handleContentUri(Uri beamUri) {// Position of the filename in the query Cursorint filenameIndex;// File object for the filenameFile copiedFile;// The filename stored in MediaStoreString fileName;// Test the authority of the URIif (!TextUtils.equals(beamUri.getAuthority(), MediaStore.AUTHORITY)) {/** Handle content URIs for other content providers*/// For a MediaStore content URI} else {// Get the column that contains the file nameString[] projection = { MediaStore.MediaColumns.DATA };Cursor pathCursor =getContentResolver().query(beamUri, projection,null, null, null);// Check for a valid cursorif (pathCursor != null &&pathCursor.moveToFirst()) {// Get the column index in the CursorfilenameIndex = pathCursor.getColumnIndex(MediaStore.MediaColumns.DATA);// Get the full file name including pathfileName = pathCursor.getString(filenameIndex);// Create a File object for the filenamecopiedFile = new File(fileName);// Return the parent directory of the filereturn new File(copiedFile.getParent());} else {// The query didn't work; return nullreturn null;}}}...如果要學習更多從內容提供者中接收數據的其它知識,請參見章節:Retrieving Data from the Provider.
總結
以上是生活随笔為你收集整理的Android官方开发文档Training系列课程中文版:通过NFC共享文件之从其它设备接收文件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 多任务学习方法
- 下一篇: 【数据挖掘】数据预处理