實例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
→調用方法啓動訪問
→當得到了服務器的返回信息,處理信息。