注:本文翻譯自Google官方的Android Developers Training文檔,譯者技術(shù)一般,由于喜愛安卓而產(chǎn)生了翻譯的念頭,純屬個人興趣愛好。
原文鏈接: http://developer.android.com/training/beam-files/receive-files.html
Android Beam文件傳輸將文件拷貝至接收設(shè)備上的一個特殊目錄。同時使用Android媒體掃描器 ( Android Media Scanner )掃描拷貝的文件,并為媒體文件添加對應(yīng)的字段至媒體庫( MediaStore ?provide)中。這節(jié)課將向你展示當(dāng)文件拷貝完成時要如何響應(yīng),并且在接收設(shè)備上應(yīng)該如何放置拷貝的文件。
一). 響應(yīng)需求以顯示數(shù)據(jù)
當(dāng)Android Beam文件傳輸將文件拷貝至接收設(shè)備后,它會發(fā)布一個通知,包含了一個
Intent
,它有有一個
ACTION_VIEW
的行為,第一個傳輸文件的
MIME
類型,和一個指向第一個文件的
URI。當(dāng)用戶點擊了這個通知后,intent會被發(fā)送至系統(tǒng)。為了讓你的應(yīng)用能夠響應(yīng)這個intent,為要響應(yīng)的
Activity
所對應(yīng)的
<activity>
標(biāo)簽添加
<intent-filter>
標(biāo)簽,在
<intent-filter>
標(biāo)簽中,添加下面的子標(biāo)簽:
<action android:name="android.intent.action.VIEW" />
用來匹配從通知發(fā)送的intent。
<category android:name="android.intent.category.CATEGORY_DEFAULT" />
匹配隱式的 Intent 。
<data android:mimeType=" mime-type " />
匹配一個MIME類型。要指定那些你的應(yīng)用能夠處理的類型。
例如,下面的例子展示了如何添加一個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文件傳輸會發(fā)送含有 ACTION_VIEW 的intent。在接收設(shè)備上的其它應(yīng)用也有可能會發(fā)送含有該行為的intent。我們馬上會進一步討論這一問題。
二). 需求文件權(quán)限
如果要讀取Android Beam文件傳輸所拷貝到設(shè)備上的文件,需要 READ_EXTERNAL_STORAGE 權(quán)限。例如:
< uses-permission android:name ="android.permission.READ_EXTERNAL_STORAGE" />
如果你希望將文件拷貝指你自己應(yīng)用的存儲區(qū),那么需要的權(quán)限改為 WRITE_EXTERNAL_STORAGE ,另外 WRITE_EXTERNAL_STORAGE 權(quán)限包含了 READ_EXTERNAL_STORAGE 權(quán)限。
Note:
對于Android 4.2.2 (API Level 17), READ_EXTERNAL_STORAGE 權(quán)限僅在用戶選擇要讀文件時才是強制需要的。而在今后的版本中會在所有情況下都需要該權(quán)限。為了保證應(yīng)用在未來的兼容性,建議在清單文件中申明該權(quán)限。
由于你的應(yīng)用對于其 內(nèi)部 存儲區(qū)域具有控制權(quán),所以若要將文件拷貝至你應(yīng)用的 內(nèi)部 存儲區(qū)域,寫權(quán)限式不需要申明的。
三). 獲取拷貝文件的目錄
Android Beam文件傳輸一次性將所有文件拷貝到目標(biāo)設(shè)備的一個目錄內(nèi), Android Beam文件傳輸通知所發(fā)出的 Intent 中包含有URI,他指向了第一個傳輸?shù)奈募H欢愕膽?yīng)用也有可能接收到除了 Android Beam文件傳輸之外的某個來源所發(fā)出的含有 ACTION_VIEW 行為的Intent。為了明確你應(yīng)該如何處理接收的Intent,你需要檢查它的架構(gòu)( scheme )和權(quán)威( authority )。
為了獲得URI的架構(gòu),調(diào)用 Uri.getScheme() ,下面的代碼展示了如何明確架構(gòu)并處理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 包含一個內(nèi)容URI,則該URI包含了一個文件的絕對文件名,包括了完整的路徑和文件名。對于 Android Beam文件傳輸來說,目錄路徑指向了其它傳輸文件的位置(如果有其它傳輸文件的話),要獲得這個目錄路徑,取得URI的路徑部分(URI中除去“ file: ”前綴的部分),根據(jù)路徑創(chuàng)建一個 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(); } ...
從內(nèi)容URI獲取目錄
如果接收的 Intent 包含一個內(nèi)容URI,這個URI可能指向的是一個存儲于 MediaStore 內(nèi)容提供程序的目錄和文件名。你可以通過檢測URI的權(quán)威值來判斷是否是 MediaStore 的內(nèi)容URI。一個 MediaStore 的內(nèi)容URI可能來自 Android Beam文件傳輸也可能來自其它應(yīng)用,但不管怎么樣,你都能根據(jù)該內(nèi)容URI獲得一個目錄和文件名。
你也能接收一個 ACTION_VIEW 的Intent,它包含有一個內(nèi)容提供程序的URI而不是 MediaStore ,在這個例子中,這個內(nèi)容URI不包含 MediaStore 的權(quán)威值,且這個URI一般不指向一個目錄
Note:
對于 Android Beam文件傳輸,如果第一個接收的文件,其MIME類型為“ audio/* ”,“ image/* ”或者“ video/* ”,那么你接收這個處于 ACTION_VIEW 的Intent的內(nèi)容URI。 Android Beam文件傳輸會通過在它存儲傳輸文件的目錄內(nèi)運行媒體掃描器,以此為媒體文件添加索引。同時媒體掃描器將結(jié)果寫入 MediaStore 內(nèi)容提供程序,之后它將第一個文件的內(nèi)容URI回遞給 Android Beam文件傳輸。這個內(nèi)容URI就是你在通知 Intent 中所接收到的。要獲得第一個文件的目錄,你需要使用該內(nèi)容URI從 MediaStore 中獲取它。
確定內(nèi)容提供程序
為了明確你能從內(nèi)容URI中獲取文件目錄,你可以通過調(diào)用 Uri.getAuthority() 獲取URI的權(quán)威,以此確定與該URI相關(guān)聯(lián)的內(nèi)容提供程序。其結(jié)果有兩個可能的值:
表明這個URI關(guān)聯(lián)了被 MediaStore 追蹤的 一個文件或者 多個文件。可以從 MediaStore 中獲取文件的全名,目錄名就自然可以從文件全名中獲取。
其他任何權(quán)威值
來自其他內(nèi)容提供程序的內(nèi)容URI。可以顯示與該內(nèi)容URI相關(guān)聯(lián)的數(shù)據(jù),但是不要嘗試去獲取文件目錄。
為了從
MediaStore
的內(nèi)容URI中獲取目錄,執(zhí)行一個查詢操作,它將
Uri
參數(shù)指定為收到的內(nèi)容URI,列名為
MediaColumns.DATA
。返回的
Cursor
包含了完整路徑和URI所代表的文件名。該目錄路徑下還包含了由
Android Beam文件傳輸傳送到該設(shè)備上的其它文件。
下面的代碼展示了你要如何測試內(nèi)容URI的權(quán)威值,并獲取傳輸文件的路徑和文件名:
... 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 ; } } } ...
要學(xué)習(xí)更多關(guān)于從內(nèi)容提供程序獲取數(shù)據(jù)的知識,可以閱讀: Retrieving Data from the Provider 。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

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