Android官方开发文档Training系列课程中文版:分享文件之分享一个文件
原文地址:http://android.xsoftlab.net/training/secure-file-sharing/share-file.html
一旦APP設(shè)置通過URI的方式共享文件,你需要響應(yīng)其它APP請(qǐng)求這些文件的請(qǐng)求。響應(yīng)這些請(qǐng)求的一種方式是,在服務(wù)端APP上提供一個(gè)文件選擇接口,以便其它的程序可以調(diào)用。這種方法允許客戶端程序的用戶從服務(wù)端選擇一個(gè)文件,然后接收被選擇文件的URI地址。
這節(jié)課展示了如何在Activity中創(chuàng)建文件選擇功能,以便響應(yīng)文件請(qǐng)求。
接收文件請(qǐng)求
為了接收客戶端APP的文件請(qǐng)求,以及以URI的方式作出響應(yīng),APP應(yīng)該在Activity中提供文件選擇器。這樣的話,客戶端APP可以通過調(diào)用startActivityForResult()方法啟動(dòng)這個(gè)Activity。當(dāng)客戶端調(diào)用了startActivityForResult()方法,你的APP可以返回一個(gè)結(jié)果給客戶端APP,這個(gè)結(jié)果以URI的形式將用戶選擇的文件返回。
有關(guān)學(xué)習(xí)如何在客戶端APP中實(shí)現(xiàn)文件的請(qǐng)求,請(qǐng)參見課程: Requesting a Shared File。
創(chuàng)建一個(gè)文件選擇器Activity
為了設(shè)置文件選擇器Activity,首選需要在清單文件中指定activity,并在其中附加意圖過濾器,這個(gè)意圖過濾器用來匹配行為ACTION_PICK以及類別CATEGORY_DEFAULT和CATEGORY_OPENABLE。還要給服務(wù)端給客戶端提供的文件添加MIME類型過濾器。下面的代碼片段展示了如何指定一個(gè)新Activity以及過濾器:
<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>在代碼中定義文件選擇器
接下來,定義一個(gè)Activity來展示內(nèi)部存儲(chǔ)器中files/images/目錄下的可用文件,并允許用戶來選擇需要的文件。下面這段代碼演示了如何定義一個(gè)Activity來響應(yīng)用戶的選擇:
public class MainActivity extends Activity {// The path to the root of this app's internal storageprivate File mPrivateRootDir;// The path to the "images" subdirectoryprivate File mImagesDir;// Array of files in the images subdirectoryFile[] mImageFiles;// Array of filenames corresponding to mImageFilesString[] mImageFilenames;// Initialize the Activity@Overrideprotected void onCreate(Bundle savedInstanceState) {...// Set up an Intent to send back to apps that request a filemResultIntent =new Intent("com.example.myapp.ACTION_RETURN_FILE");// Get the files/ subdirectory of internal storagemPrivateRootDir = getFilesDir();// Get the files/images subdirectory;mImagesDir = new File(mPrivateRootDir, "images");// Get the files in the images subdirectorymImageFiles = mImagesDir.listFiles();// Set the Activity's result to null to begin withsetResult(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)文件選擇器
一旦用戶選擇了被共享的文件,你的程序必須檢查哪一個(gè)文件被選中,并且生成該文件的URI地址。前面的部分Activity在ListView中展示了可用的文件列表,當(dāng)用戶點(diǎn)擊了文件的名稱,隨之系統(tǒng)會(huì)調(diào)用方法onItemClick(),在這個(gè)方法中你可以獲取到被選中的文件。
在onItemClick()方法中,從被選擇的文件中獲得文件的File對(duì)象,然后將這個(gè)對(duì)象作為參數(shù)傳遞給getUriForFile(),它會(huì)伴隨著權(quán)限一并加入,這個(gè)權(quán)限是由 < provider>元素指定的。結(jié)果URI會(huì)包含權(quán)限、文件在相應(yīng)目錄中的路徑段(在XML meta-data中指定的部分)以及文明的名稱和其擴(kuò)展部分。有關(guān)FileProvider如何映射meta-data與路徑段的目錄,請(qǐng)看章節(jié)Specify Sharable Directories。
下面的代碼段展示了如何檢測(cè)被選擇的文件以及獲取該文件的URI:
protected void onCreate(Bundle savedInstanceState) {...// Define a listener that responds to clicks on a file in the ListViewmFileListView.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 URItry {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);}...}});...}要記住,你只可以對(duì)在< paths>元素中指定目錄下的文件進(jìn)行URI編碼,就像Specify Sharable Directories這節(jié)課中描述的一樣。如果你對(duì)getUriForFile()方法中傳入的File參數(shù)并沒有在< path>元素中指定,那么你會(huì)收到一個(gè) IllegalArgumentException異常。
對(duì)文件授予權(quán)限
現(xiàn)在對(duì)將要分享的文件有了一個(gè)URI,你需要允許客戶端APP來訪問這個(gè)文件。為了允許訪問,需要通過添加URI到一個(gè)Intent上,并且在這個(gè)Intent上設(shè)置權(quán)限標(biāo)志。產(chǎn)生的這個(gè)權(quán)限是個(gè)臨時(shí)權(quán)限,并且會(huì)在接收端APP任務(wù)結(jié)束的時(shí)候自動(dòng)終止。
下面這段代碼展示了如何對(duì)文件設(shè)置讀取權(quán)限:
protected void onCreate(Bundle savedInstanceState) {...// Define a listener that responds to clicks in the ListViewmFileListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> adapterView,View view,int position,long rowId) {...if (fileUri != null) {// Grant temporary read permission to the content URImResultIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);}...}...});...}Caution:安全的對(duì)文件授予臨時(shí)訪問權(quán)限,setFlags()是唯一的方式。要避免對(duì)文件的URI使用Context.grantUriPermission()方法,因?yàn)樵摲椒ㄊ谟璧臋?quán)限只可以通過Context.revokeUriPermission()方法撤銷。
對(duì)客戶端APP共享文件
如果要共享文件給客戶端APP,需要傳遞一個(gè)Intent給setResult(),這個(gè)Intent包含了文件的URI以及訪問權(quán)限。當(dāng)你定義的這個(gè)Activity結(jié)束時(shí),系統(tǒng)會(huì)發(fā)送這個(gè)Intent給客戶端APP,下面這段代碼展示了如何實(shí)現(xiàn)這部分功能:
protected void onCreate(Bundle savedInstanceState) {...// Define a listener that responds to clicks on a file in the ListViewmFileListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> adapterView,View view,int position,long rowId) {...if (fileUri != null) {...// Put the Uri and MIME type in the result IntentmResultIntent.setDataAndType(fileUri,getContentResolver().getType(fileUri));// Set the resultMainActivity.this.setResult(Activity.RESULT_OK,mResultIntent);} else {mResultIntent.setDataAndType(null, "");MainActivity.this.setResult(RESULT_CANCELED,mResultIntent);}}});一旦用戶選擇了文件,那么就應(yīng)該立即帶用戶返回客戶端APP。實(shí)現(xiàn)這種方式的一種方法就是提供一個(gè)鉤形符號(hào)或者結(jié)束按鈕。使用Button的android:onClick屬性與對(duì)應(yīng)的Button相關(guān)聯(lián)。在方法中。調(diào)用finish()方法:
public void onDoneClick(View v) {// Associate a method with the Done buttonfinish();}總結(jié)
以上是生活随笔為你收集整理的Android官方开发文档Training系列课程中文版:分享文件之分享一个文件的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java】Object类、Object
- 下一篇: 数据库的方向 - 行vs列(转自: IB