FileProvider的Server和Client

實例1

ServerTest

當你配置了FileProvider,且當有應用向你請求文件時,你需提供一個窗體,該窗體能實現如下功能:(三步)
→可以被請求文件的應用喚起(就是能被隱式Intent喚起)。
→將自己能夠分享的文件顯示在窗體裏(你可以用ListView實現,安卓官方教程也以這個控件作爲例子實現)。
→當用戶點擊了某個文件,該窗體能提供這個文件的URL(就是將URL返回給調用他的窗體)。

配置清單文件的過濾器
AndroidManifest.xml

<activity
    android:name=".ShowFile"
    android:label="@string/title_activity_show_file"
    android:theme="@style/AppTheme.NoActionBar">
    <intent-filter>
        <action android:name="android.intent.action.PICK"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain"/>
        <data android:mimeType="image/*"/>
    </intent-filter>
</activity>

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.example.servertest.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

在res裏面創建一個xml文件夾,在裏面再創建一個file_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="my_images" path="/images"/>
</paths>

content_show_file.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
        android:id="@+id/file_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>

showFile.class
通過配置ListView實現(我的代碼將分享的路徑:手機內存/files/images/ )

public class ShowFile extends AppCompatActivity {

    private File filesDir;//他將指向內存路徑files
    private File imageDir;//指向images子路徑的:files/images
    private File[] imageFiles;//images子路徑的所有文件
    private String[] imageFileNames;//images子路徑的所有文件名字
    private Uri fileUri;//image圖片地址
    private Intent resultIntent;//返回的intent

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.content_show_file);

        //獲取ListView
        ListView fileListView = (ListView)findViewById(R.id.file_list);
        //設置Intent
        resultIntent = new Intent("com.example.clienttest.ACTION_RETURN_FILE");
        //獲取文件路徑以及名字
        filesDir = Environment.getExternalStorageDirectory();
        imageDir = new File(filesDir, "images");

        //判斷目錄是否存在
        if(!imageDir.exists()){
            imageDir.mkdirs();
            try{
                File file = new File(imageDir,"picture.jpg");
                OutputStream out = new FileOutputStream(file);
                Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.picture);
                //把drawable下的圖片拷貝到sdcard的images目錄下
                bitmap.compress(Bitmap.CompressFormat.JPEG,90,out);
                out.flush();
                out.close();
            }catch (IOException e){
                e.printStackTrace();
            }
        }

        //獲取images子路徑下所有文件
        imageFiles = imageDir.listFiles();
        //將文件的名字裝填
        imageFileNames = new String[imageFiles.length];
        for(int i = 0; i<imageFiles.length; i++){
            imageFileNames[i] = imageFiles[i].getName();
        }

         /*
           通過ListView將文件的名字顯示出來
           同時設置ListView響應用戶對文件的選擇
        */
        fileListView.setAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,imageFileNames));
        fileListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int postion, long l) {
                Log.e("server","1");
                File requestFile = new File(imageDir,imageFileNames[postion]);
                try{
                    //標識爲"com.example.servertest.provider"的FileProvider獲取到文件requestFile,並返回被封裝過的URI
                    fileUri = FileProvider.getUriForFile(ShowFile.this,
                            "com.example.servertest.fileprovider",requestFile);
                }catch (Exception e){
                    e.printStackTrace();
                }

                /*
                  當用戶選擇了某個文件,而且服務器成功地得到文件的URI,將URI返回給客戶端。
                */
                if(fileUri!=null){

                    //爲RUI添加訪問權限
                    resultIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                    //設置數據以及數據類型
                    resultIntent.setDataAndType(fileUri,getContentResolver().getType(fileUri));
                    ShowFile.this.setResult(RESULT_OK,resultIntent);
                    finish();
                } else {
                    resultIntent.setDataAndType(null,"");
                    ShowFile.this.setResult(RESULT_CANCELED,resultIntent);
                    finish();
                }
            }
        });
    }

}

現在,服務器的設置已經完成,當有應用需要請求文件,你將可以將你自己的文件給提供出去

△總結:到底服務器都做了什麼
→配置FileProvider,指定authorities,指定可分享文件的那個路徑(通過配置xml文件)。
→配置,使他能被客戶端的隱式Intent喚起。
→配置ListView,當服務器被喚起時,提供一個可被分享的文件的列表。
→配置點擊事件響應,當客戶端選擇文件,生成文件的URI,同時提供相關權限,並且將該文件的URI給客戶端(setResult()方法)。




ClientTest

概述:客戶端即請求獲取某些文件的應用程序。
客戶端要做些什麼:
→配置Intent,指定客戶端想請求訪問什麼文件
(1)intent.setAction(Intent.ACTION_PICK);
(2)intent.setType(“image/*”);
→啓動訪問:當用戶想訪問某些文件,一般情況下,應當是在某個按鈕點擊事件響應函數裏面執行:執行方法: startActivityForResult(intent, 0);
→當服務器提供了想要的文件,客戶端要處理自己所得到的文件。
onActivityResult(int requestCode, int resultCode, Intent returnIntent);
方法裏面,returnIntent參數,他帶着從服務器裏返回來的文件URL,通過他來打開我們想訪問的文件

AndroidManifest.xml

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <action android:name="com.example.clienttest.ACTION_RETURN_FILE"/>
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="獲取圖片"/>

    <TextView
        android:id="@+id/file_uri"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/file_type"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/file_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/file_size"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <ImageView
        android:id="@+id/imageview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

MainActivity.class

public class MainActivity extends AppCompatActivity {

    private TextView fileUri;
    private TextView fileType;
    private TextView fileName;
    private TextView fileSize;
    private ImageView imageView;
    private Intent requestIntent;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        requestIntent = new Intent(Intent.ACTION_PICK);
        requestIntent.setType("image/jpg");

        Button button = (Button) findViewById(R.id.button);
        fileUri = (TextView) findViewById(R.id.file_uri);
        fileType = (TextView) findViewById(R.id.file_type);
        fileName = (TextView) findViewById(R.id.file_name);
        fileSize = (TextView) findViewById(R.id.file_size);
        imageView = (ImageView) findViewById(R.id.imageview);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                startActivityForResult(requestIntent,0);
            }
        });

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case 0:
                if (resultCode == RESULT_OK) {
                    Uri returnUri = data.getData();
                    fileUri.setText("uri: " + returnUri);
                    fileType.setText("type: " + getContentResolver().getType(returnUri));
                    Cursor cursor = getContentResolver().query(returnUri, null, null, null, null);
                    int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
                    int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
                    cursor.moveToNext();
                    fileName.setText("name: " + cursor.getString(nameIndex));
                    fileSize.setText("size: " + cursor.getLong(sizeIndex));
                    imageView.setImageURI(returnUri);
                }
                break;
            default:
                break;

        }
    }
}

當服務器窗體退出之後,客戶端的onActivityResult()將被調用。returnIntent參數,就是服務器返回的Intent。Intent包含了文件URI,URI裏包含文件各種信息。openFileDescriptor()方法返回ParcelFileDesctiptor,通過ParcelFileDescriptor實例,可以得到FileDescriptor對象,客戶端可以通過”FileDescriptor”對象讀取那個文件。

△總結:客戶端到底做了什麼事
→配置一個啓動服務器的Intent
→調用方法啓動訪問
→當得到了服務器的返回信息,處理信息。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章