安卓下的文件分享——FileProvider

来源:互联网 发布:孙俪的淘宝店铺等花开 编辑:程序博客网 时间:2024/05/20 08:26


分享文件

△概述:如果你要对外提供少量数据,你可以用Intent带着少量数据出去,当你需要对外提供大批量的数据(比如一个图片编辑软件向你请求一个图片资源,一个文档编辑器向你请求一个文档)你将需要分享文件。

△服务器与客户端:我们将请求文件的应用称为客户端,将对外提供数据的应用称为服务器。

△这里所说的文件分享,不是一个应用程序主动分享文件出去(这个功能有其他的实现方式),而是当有应用想要请求文件,你的应用可以将相应的文件提供出去。比如一个社交软件准备发送一张图片,社交软件就相当于是客户端,系统内置那个图库就相当于是服务器,社交软件向图库请求一个图片文件。

  

服务器的具体步骤如下

配置FileProvider

  △想将文件分享出去,首先需要定义一个文件分享者:FileProvider,步骤如下:在配置文件里面增加provider标签:<provider></provider>,这个标签需要指定如下信息:

      →指定FileProvider的类。

      →指定“authority”属性,通常该属性值一般会是:”包名.fileProvider”。,当FileProvider为你的文件生成URIs时,authorities就是URIs的URI字段内容。

      →一个xml文件,你的应用只能将指定的某些路径下的文件分享出去,这些路径由你通过这个XML文件指定。

注:

      →xml文件由meta-data子元素来指定。

<providerandroid:name="android.support.v4.content.FileProvider"android.authorities="com.test.fileprovider.fileprovider"android:grantUriPermissions="true"android:exported="false"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:name="@xml/filepaths"/></provider>

我当前的包名是:com.test.fileprovider。

 

△创建上一步所说的XML文件

    →在res目录下面新建文件夹,取名xml,在文件夹新建一个文件,取名:filepaths(你可以取你喜欢的名字),

这是按照上图当中resource内容创建。

    →xml文件内容:

<?xml version="1.0" encoding="utf-8"?><path><!--paths表示你要分享哪个路径下的文件--><files-path path="images/" name="myimages"/></path>


解析:

    →到此为止,你已经拥有了一个完整的FileProvider。他配置了authority,你想要分享的文件所在路径(或者说是你的应用程序能够分享出去的文件的路径)。

 

    →现在,xml文件指定了如下路径:/data/data/包名/files/images。其实就是你的应用调用方法:getFilesDir()所返回的路径下的images子路径:files/images/。

 

    →name属性内容与文件的路径没有关系,他是你想要在你的URI里面插入的一个字段,如果你在files/images/路径下面有个文件名叫:myImage.jpg。那么fileprovider将会返回:

content://com.test.fileprovider.fileprovider/myimages/myImage.jpg。我们看到,最终的URI里面没有包含images子路径名,而且包含了一个你想插入的name。name属性其实就是为了隐藏真实的路径的。


    →所以最终URI是:content://你在清单文件里面所指定的“authority”属性/你的xml文件里指定name属性/你的文件的全名。

 

    →注:在<paths></paths>标签里面你还可以添加多个元素:<cache-path>(对应路径:/data/data/包名/cache)或者<external-path>(对应你的应用程序在SD卡上的默认路径)。

 

 

设置一个文件展示以及选择用的窗体

△当你配置了FileProvider,且当有应用向你请求文件时,你需提供一个窗体,该窗体能实现如下功能:(三步)

    →可以被请求文件的应用唤起(就是能被隐式Intent唤起)。

    →将自己能够分享的文件显示在窗体里(你可以用ListView实现,安卓官方教程也以这个控件作为例子实现)。

    →当用户点击了某个文件,该窗体能提供这个文件的URL(就是将URL返回给调用他的窗体)。

 

△第一步:配置清单文件的过滤器

<activityandroid:name="com.test.fileprovider.ShowFile"><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>


△第二步:通过配置ListView实现(我的代码将分享的路径:手机内存/files/images/,至于如何在内存里创建一个images文件夹,我在这里不再重复)

package com.test.fileprovider;import java.io.File;public class ShowFile extends Activity {//创建将用到得变量//这些变量主要用于显示一个将分享的文件列表private File filesDir;//他将指向内存路径filesprivate File imageDir;//指向images子路径的:files/imagesprivate File[] imageFiles;//images子路径的所有文件private String[] imageFileNames;//images子路径的所有文件名字private ListView myFileListView = null;private Uri fileUri = null;Intent resultIntent = null;//对变量进行初始化//将文件的名字装填@Overrideprotected void onCreate(bundle savedInstanceState){// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.file_select_activity);//获取ListViewmyFileListView = (ListView)findViewById(R.id.lv_file);//设置IntentresultIntent = new Intent("com.test.fileprovider.ACTION_RETURN_FILE");//获取文件路径以及名字filesDir = getFilesDir();imageDir = new File(filesDir,"images");imageFiles = imageDir.listFiles();//获取images子路径下所有文件//将文件的名字装填imageFileNames = new String[imageFiles.length];for(int i = 0; i<imageFiles.length; i++){imageFileNames[i] = imageFiles[i].getName();}setResult(Activity.RESULT_CANCELED, null);//设置一个默认的返回值/*通过ListView将文件的名字显示出来同时设置ListView响应用户对文件的选择*///将文件名显示出来myFileListView.setAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,imageFileNames));//监听myFileListView.setOnItemClickListener(new AdapterView.OnItemClickListener(){@Overridepublic void onItemClick(AdapterView<?> parent,View view, int position, long id){// TODO Auto-generated method stub//记录哪个文件被选中了File requestFile = new File(imageDir,imageFileNames[position]);try{//获取文件的URIfileUri = FileProvider.getUriForFile(ShowFile.this,"com.test.fileprovider.fileprovider",requestFile); }catch(Exception e){// TODO: handle exception}/*第三步:当用户选择了某个文件,而且服务器成功地得到文件的URI,将URI返回给客户端。*///如果成功得到了URIif(fileUri!=null){//为RUI添加访问权限resultIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//设置数据以及数据类型resultIntent.setDataAndType(fileUri, getContentResolver().getType(fileUri));ShowFile.this,setResult(RESULT_OK,resultIntent);}else {resultIntent.setDataAndtype(null, "");ShowFile.this.setResult(RESULT_CANCELED,)}}//OnItemClick方法体});//setOnItemClickListener}//onCreate方法//这是一个点击事件响应函数//当用户已选择完毕//提供一个按钮按下那时退出窗体public void finished(View view){finish();}}



现在,服务器的设置已经完成,当有应用需要请求文件,你将可以将你自己的文件给提供出去

 

△总结:到底服务器都做了什么

    →配置FileProvider,指定authorities,指定可分享文件的那个路径(通过配置xml文件)。

    →配置<intent-filter>,使他能被客户端的隐式Intent唤起。

    →配置ListView,当服务器被唤起时,提供一个可被分享的文件的列表。

    →配置点击事件响应,当客户端选择文件,生成文件的URI,同时提供相关权限,并且将该文件的URI给客户端(setResult()方法)。

 

客户端

 

△概述:客户端即请求获取某些文件的应用程序。

△客户端要做些什么:

    →配置Intent,指定客户端想请求访问什么文件

      (1)intent.setAction(Intent.ACTION_PICK);

      (2)intent.setType(“image/*”);

    →启动访问:当用户想访问某些文件,一般情况下,应当是在某个按钮点击事件响应函数里面执行:执行方法: startActivityForResult(intent, 0);

    →当服务器提供了想要的文件,客户端要处理自己所得到的文件。

onActivityResult(int  requestCode, int  resultCode, Intent  returnIntent);

方法里面,returnIntent参数,他带着从服务器里返回来的文件URL,通过他来打开我们想访问的文件

 

△第一步:配置Intent

//下面哪些TextView用来显示文件信息//只是方便我调试时使用import java.io.FileDescriptor;public class MainActivity extends Activity {private Intent requestIntent = null;private ParcelFileDescriptor mInputPFD = null;//这些TextView都是用来显示文件相关信息private TextView filesUriTextView = null;private TextView fileNameTextView = null;private TextView fileSizeTextView = null;private TextView fileTypeTextView = null;@Overrideprotected void onCreate(Bundle saveInstanceState){super.onCreate(saveInstanceState);setContentView(R.layout.main);requestIntent = new Intent(Intent.ACTION_PICK);requestIntent.setType("image/jpg");//当获取到文件的URI//使用TextView将文件的相关信息显示出来filesUriTextView = (TextView)findViewById(R.id.tv_files_uri);fileNameTextView = (TextView)findViewById(R.id.tv_file_name);fileSizeTextView = (TextView)findViewById(R.id.tv_files_size);fileTypeTextView = (TextView)findViewById(R.id.tv_files_type);}/*第二部:启动访问*///点击事件响应函数public void getsFile(View view){startActivityForResult(requestIntent, 0);}/*第三步:客户端通过RUI处理所得到的文件,以及获取文件相关信息*/@overrideprotected void onActivityResult(int requestCode,int resultCode,Intent returnIntent){// TODO Auto-generated method stubsuper.onActivityResult(requestCode,resultCode,returnIntent);//如果不是正常返回if(resultCode!=RESULT_OK){return;}else{Uri returnUri = returnIntent.getData();//这个方法是自己写来的//用它来获取文件的相关信息getFileInfos(returnUri);try{}catch(FileNotFoundException e){e.printStackTrace();return;}FileDescriptor fd = mInputPFD.getFileDescriptor();}//if}//getFileInfos方法private void getFileInfos(Uri uri){filesUriTextView.setText("uri:"+uri);fileTypeTextView.setText("文件类型:"+getContentResolver.getType(uri));Cursor returnCursor = getContentResolver().query(uri,null,null,null,null);int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);returnCursor.moveToFirst();fileNameTextView.setText("文件名字:"+returnCursor.getString(nameIndex));fileSizeTextView.setText("尺寸:"+returnCursor.getLong(sizeIndex));}}

解析:当服务器窗体退出之后,客户端的onActivityResult()将被调用。returnIntent参数,就是服务器返回的Intent。Intent包含了文件URI,URI里包含文件各种信息。openFileDescriptor()方法返回ParcelFileDesctiptor,通过ParcelFileDescriptor实例,可以得到FileDescriptor对象,客户端可以通过”FileDescriptor”对象读取那个文件。

/*

到此为止你已经得到了一个客户端的程序

*/

 

△总结:客户端到底做了什么事

    →配置一个启动服务器的Intent

    →调用方法启动访问

    →当得到了服务器的返回信息,处理信息。


0 0
原创粉丝点击