|
這篇文章主要介紹了適配Android 10(Q)后,調(diào)用系統(tǒng)拍照,系統(tǒng)相冊,系統(tǒng)裁剪和上傳問題,這是一個(gè)很常用的功能,但是在Android 6.0,Android 7.0和Android 10.0以上版本的實(shí)現(xiàn)都有所不同,這篇文章從Android 4適配到Android 10。 之前寫畢設(shè)的時(shí)候,在寫上傳頭像的功能時(shí),參考網(wǎng)上的方法寫了一大堆,在我的手機(jī)(Android 9)上可以正常運(yùn)行,當(dāng)時(shí)沒多想,以為高版本可以向下兼容,后來我把程序發(fā)給同學(xué)去試驗(yàn),結(jié)果都告訴我上傳頭像用不了,一問才知道他們用的是Android 10的手機(jī),于是只能上網(wǎng)查找原因,然后發(fā)現(xiàn)Android 10的存儲(chǔ)方式發(fā)生了變化,Android 10的文件系統(tǒng)采用了沙盒文件系統(tǒng),最顯著的變化就是文件系統(tǒng)變安全了,于是app也沒辦法拿到外部文件的絕對路徑了,網(wǎng)上給出的方法就是將共享文件復(fù)制到沙盒目錄下,然后再進(jìn)行文件操作。話不多說,上代碼。 在文件清單AndroidManifest.xml中添加權(quán)限: 1 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><!-- 儲(chǔ)存卡的讀權(quán)限 -->2 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><!-- 儲(chǔ)存卡的寫權(quán)限 -->3 <uses-permission android:name="android.permission.CAMERA" /><!-- 調(diào)用相機(jī)權(quán)限 --> 在官方7.0的以上的系統(tǒng)中,嘗試傳遞 file://URI可能會(huì)觸發(fā)FileUriExposedException,使用FileProvider來共享文件,AndroidManifest.xml: <application ... <!-- 兼容Android7.0拍照閃退 --> <provider android:name="androidx.core.content.FileProvider" android:authorities="com.example.camera.test" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> </application> 在主界面放一個(gè)ImageView和兩個(gè)按鈕,activity_main.xml: <?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas./apk/res/android" xmlns:tools="http://schemas./tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <ImageView android:id="@+id/image" android:layout_width="250dp" android:layout_height="250dp" android:layout_marginTop="20dp" android:layout_gravity="center_horizontal"/> <TextView android:id="@+id/tv_camera" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="50dp" android:text="相機(jī)" android:textSize="18sp" android:textColor="#FFF" android:padding="10dp" android:background="#1878FF" android:layout_marginHorizontal="20dp" android:gravity="center_horizontal"/> <TextView android:id="@+id/tv_album" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="50dp" android:text="相冊" android:textSize="18sp" android:textColor="#FFF" android:padding="10dp" android:background="#1878FF" android:layout_marginHorizontal="20dp" android:gravity="center_horizontal"/></LinearLayout> 接下來是主頁面的代碼: 獲取控件,對兩個(gè)按鈕添加點(diǎn)擊監(jiān)聽,判斷權(quán)限: private ImageView image; private TextView tvCamera, tvAlbum; @Override 權(quán)限申請回調(diào): @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case PHOTO_REQUEST_CAMERA: //相機(jī)權(quán)限請求回調(diào)
if (grantResults.length > 0) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED && grantResults[2] == PackageManager.PERMISSION_GRANTED) { //跳轉(zhuǎn)相機(jī) openCamera();
} else { //無權(quán)限提示
Toast.makeText(context, "權(quán)限未通過", Toast.LENGTH_SHORT).show();
}
} break; case PHOTO_REQUEST_ALBUM: if (grantResults.length > 0) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED) { //跳轉(zhuǎn)相冊 openAlbum();
} else { //無權(quán)限提示
Toast.makeText(context, "權(quán)限未通過", Toast.LENGTH_SHORT).show();
}
} break;
}
}跳轉(zhuǎn)相機(jī): = (activity != && context != && intent.resolveActivity(activity.getPackageManager()) != = uri = file = (file != (Build.VERSION.SDK_INT >= uri = FileProvider.getUriForFile(context, "com.example.camera.test"=="相機(jī)保存的圖片Uri:" + (uri != Android 10以上的創(chuàng)建Uri,Uri創(chuàng)建在沙盒內(nèi): contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/0/"); 以上設(shè)置的保存路徑為:".../包名/files/Pictures/0",可按需更改 用于保存拍照之后的照片: private Uri createImageUri(@NonNull Context context){
String status = Environment.getExternalStorageState();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, SAVE_AVATAR_NAME);
contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/*");
contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/0/"); //判斷是否有SD卡
if (status.equals(Environment.MEDIA_MOUNTED)){ return context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
} else { return context.getContentResolver().insert(MediaStore.Images.Media.INTERNAL_CONTENT_URI, contentValues);
}
}Android 10以下的返回一個(gè)file來保存拍照后的圖片: private File createImageFile(@NonNull Context context){
File file = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES); if (file != null && !file.exists()){ if (file.mkdir()){
Log.e(TAG, "文件夾創(chuàng)建成功");
} else {
Log.e(TAG, "file為空或者文件夾創(chuàng)建失敗");
}
}
File tempFile = new File(file, SAVE_AVATAR_NAME);
Log.e(TAG, "臨時(shí)文件路徑:" + tempFile.getAbsolutePath()); if (!Environment.MEDIA_MOUNTED.equals(EnvironmentCompat.getStorageState(tempFile))){ return null;
} return tempFile;
}跳轉(zhuǎn)相冊: private void openAlbum(){
Intent intent = new Intent(Intent.ACTION_PICK, null);
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
startActivityForResult(intent, ALBUM_REQUEST_CODE);
}跳轉(zhuǎn)裁剪,裁剪在相機(jī)拍照后跳轉(zhuǎn),用一個(gè)file來加載: private void openCrop(Uri uri){ if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) && context != null){
file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES + "/0"), SAVE_AVATAR_NAME);
}
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
intent.setDataAndType(uri, "image/*"); // 設(shè)置裁剪
intent.putExtra("crop", "true"); // aspectX aspectY 是寬高的比例
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1); // 裁剪后輸出圖片的尺寸大小
intent.putExtra("outputX", 250);
intent.putExtra("outputY", 250); //適配Android10,存放圖片路徑 intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file)); // 圖片格式
intent.putExtra("outputFormat", "PNG");
intent.putExtra("noFaceDetection", true);// 取消人臉識別
intent.putExtra("return-data", true);// true:不返回uri,false:返回uri startActivityForResult(intent, TAILOR_REQUEST_CODE);
}跳轉(zhuǎn)相機(jī)、相冊和裁剪的回調(diào),如果有上傳需求的,直接上傳代碼中的file即可: @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == -1){ //回調(diào)成功
switch (requestCode) { case CAMERA_REQUEST_CODE: //相機(jī)回調(diào)
Log.e(TAG, "相機(jī)回調(diào)"); if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { //照片裁剪 openCrop(imageUri);
} else {
Toast.makeText(context, "未找到存儲(chǔ)卡", Toast.LENGTH_SHORT).show();
} break; case ALBUM_REQUEST_CODE: //相冊回調(diào)
Log.e(TAG, "相冊回調(diào)"); if (data != null && data.getData() != null) {
image.setImageURI(data.getData()); //如果需要上傳操作的可以使用這個(gè)方法
File file = FileUtils.uriToFile(data.getData(), context); //這里的file就是需要上傳的圖片了 } break; case TAILOR_REQUEST_CODE: //圖片剪裁回調(diào)
Log.e(TAG, "圖片剪裁回調(diào)");// Glide.with(context).load(file).into(image);
Uri uri = Uri.fromFile(file);
image.setImageURI(uri); //如果需要上傳全局的這個(gè)file就是需要上傳的圖片了
File file = this.file; break;
}
} else {
Toast.makeText(context, "取消", Toast.LENGTH_SHORT).show();
}
} |
|
|