注:本文翻譯自Google官方的Android Developers Training文檔,譯者技術一般,由于喜愛安卓而產生了翻譯的念頭,純屬個人興趣愛好。
原文鏈接: http://developer.android.com/training/beam-files/receive-files.html
Android Beam文件傳輸將文件拷貝至接收設備上的一個特殊目錄。同時使用Android媒體掃描器 ( Android Media Scanner )掃描拷貝的文件,并為媒體文件添加對應的字段至媒體庫( MediaStore ?provide)中。這節課將向你展示當文件拷貝完成時要如何響應,并且在接收設備上應該如何放置拷貝的文件。
一). 響應需求以顯示數據
當Android Beam文件傳輸將文件拷貝至接收設備后,它會發布一個通知,包含了一個
Intent
,它有有一個
ACTION_VIEW
的行為,第一個傳輸文件的
MIME
類型,和一個指向第一個文件的
URI。當用戶點擊了這個通知后,intent會被發送至系統。為了讓你的應用能夠響應這個intent,為要響應的
Activity
所對應的
<activity>
標簽添加
<intent-filter>
標簽,在
<intent-filter>
標簽中,添加下面的子標簽:
<action android:name="android.intent.action.VIEW" />
用來匹配從通知發送的intent。
<category android:name="android.intent.category.CATEGORY_DEFAULT" />
匹配隱式的 Intent 。
<data android:mimeType=" mime-type " />
匹配一個MIME類型。要指定那些你的應用能夠處理的類型。
例如,下面的例子展示了如何添加一個intent過濾器來激活你的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 的intent。在接收設備上的其它應用也有可能會發送含有該行為的intent。我們馬上會進一步討論這一問題。
二). 需求文件權限
如果要讀取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 (API Level 17), READ_EXTERNAL_STORAGE 權限僅在用戶選擇要讀文件時才是強制需要的。而在今后的版本中會在所有情況下都需要該權限。為了保證應用在未來的兼容性,建議在清單文件中申明該權限。
由于你的應用對于其 內部 存儲區域具有控制權,所以若要將文件拷貝至你應用的 內部 存儲區域,寫權限式不需要申明的。
三). 獲取拷貝文件的目錄
Android Beam文件傳輸一次性將所有文件拷貝到目標設備的一個目錄內, Android Beam文件傳輸通知所發出的 Intent 中包含有URI,他指向了第一個傳輸的文件。然而,你的應用也有可能接收到除了 Android Beam文件傳輸之外的某個來源所發出的含有 ACTION_VIEW 行為的Intent。為了明確你應該如何處理接收的Intent,你需要檢查它的架構( scheme )和權威( authority )。
為了獲得URI的架構,調用 Uri.getScheme() ,下面的代碼展示了如何明確架構并處理URI:
public class MainActivity extends Activity { ... // A File object containing the path to the transferred files private File mParentPath; // Incoming Intent private 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 action mIntent = 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 Intent Uri 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的路徑部分(URI中除去“ file: ”前綴的部分),根據路徑創建一個 File 對象,然后獲取這個 File 的父目錄:
... public String handleFileUri(Uri beamUri) { // Get the path part of the URI String fileName = beamUri.getPath(); // Create a File object for this filename File copiedFile = new File(fileName); // Get a string containing the file's parent directory return copiedFile.getParent(); } ...
從內容URI獲取目錄
如果接收的 Intent 包含一個內容URI,這個URI可能指向的是一個存儲于 MediaStore 內容提供程序的目錄和文件名。你可以通過檢測URI的權威值來判斷是否是 MediaStore 的內容URI。一個 MediaStore 的內容URI可能來自 Android Beam文件傳輸也可能來自其它應用,但不管怎么樣,你都能根據該內容URI獲得一個目錄和文件名。
你也能接收一個 ACTION_VIEW 的Intent,它包含有一個內容提供程序的URI而不是 MediaStore ,在這個例子中,這個內容URI不包含 MediaStore 的權威值,且這個URI一般不指向一個目錄
Note:
對于 Android Beam文件傳輸,如果第一個接收的文件,其MIME類型為“ audio/* ”,“ image/* ”或者“ video/* ”,那么你接收這個處于 ACTION_VIEW 的Intent的內容URI。 Android Beam文件傳輸會通過在它存儲傳輸文件的目錄內運行媒體掃描器,以此為媒體文件添加索引。同時媒體掃描器將結果寫入 MediaStore 內容提供程序,之后它將第一個文件的內容URI回遞給 Android Beam文件傳輸。這個內容URI就是你在通知 Intent 中所接收到的。要獲得第一個文件的目錄,你需要使用該內容URI從 MediaStore 中獲取它。
確定內容提供程序
為了明確你能從內容URI中獲取文件目錄,你可以通過調用 Uri.getAuthority() 獲取URI的權威,以此確定與該URI相關聯的內容提供程序。其結果有兩個可能的值:
表明這個URI關聯了被 MediaStore 追蹤的 一個文件或者 多個文件??梢詮? MediaStore 中獲取文件的全名,目錄名就自然可以從文件全名中獲取。
其他任何權威值
來自其他內容提供程序的內容URI。可以顯示與該內容URI相關聯的數據,但是不要嘗試去獲取文件目錄。
為了從
MediaStore
的內容URI中獲取目錄,執行一個查詢操作,它將
Uri
參數指定為收到的內容URI,列名為
MediaColumns.DATA
。返回的
Cursor
包含了完整路徑和URI所代表的文件名。該目錄路徑下還包含了由
Android Beam文件傳輸傳送到該設備上的其它文件。
下面的代碼展示了你要如何測試內容URI的權威值,并獲取傳輸文件的路徑和文件名:
... public String handleContentUri(Uri beamUri) { // Position of the filename in the query Cursor int filenameIndex; // File object for the filename File copiedFile; // The filename stored in MediaStore String fileName; // Test the authority of the URI if (! 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 name String[] projection = { MediaStore.MediaColumns.DATA }; Cursor pathCursor = getContentResolver().query(beamUri, projection, null , null , null ); // Check for a valid cursor if (pathCursor != null && pathCursor.moveToFirst()) { // Get the column index in the Cursor filenameIndex = pathCursor.getColumnIndex( MediaStore.MediaColumns.DATA); // Get the full file name including path fileName = pathCursor.getString(filenameIndex); // Create a File object for the filename copiedFile = new File(fileName); // Return the parent directory of the file return new File(copiedFile.getParent()); } else { // The query didn't work; return null return null ; } } } ...
要學習更多關于從內容提供程序獲取數據的知識,可以閱讀: Retrieving Data from the Provider 。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

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