解決安卓7.0系統裁剪圖片出錯問題
下面先貼出主要用到的方法,然後在解釋裡面的所涉及到的內容:
public void startPhotoZoom(Uri uri) { File CropPhoto=new File(getExternalCacheDir(),"crop.jpg"); try{ if(CropPhoto.exists()){ CropPhoto.delete(); } CropPhoto.createNewFile();}catch(IOException e){ e.printStackTrace(); } cropImageUri=Uri.fromFile(CropPhoto); Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(uri, "image/*"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //新增這一句表示對目標應用臨時授權該Uri所代表的檔案 } // 下面這個crop=true是設定在開啟的Intent中設定顯示的VIEW可裁剪 intent.putExtra("crop", "true"); intent.putExtra("scale", true); intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); //輸出的寬高 intent.putExtra("outputX", 300); intent.putExtra("outputY", 300); intent.putExtra("return-data", false); intent.putExtra(MediaStore.EXTRA_OUTPUT, cropImageUri); intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); intent.putExtra("noFaceDetection", true); // no face detection startActivityForResult(intent, PHOTO_REQUEST_CUT); }
首先是Uri:對於Uri的理解這裡不免會出現URI和Uri兩種,首先URI位置在java.net.URI,顯然是Java提供的一個類。而Uri位置在android.net.Uri,是由Android提供的一個類。通俗點理解就是:Uri是Android開發的,擴充套件了JAVA中URI的一些功能來特定的適用於Android開發,所以大家在開發時,只使用Android 提供的Uri即可;呵呵,有木有很清楚,如果想要對Uri和URI有更多的瞭解可以參考http://blog.csdn.net/harvic880925/article/details/44679239的部落格,他的兩篇文章對Uri的講解非常的詳細哦,我對Uri的理解也是從那學的。
接下來涉及的好像就是建立資料夾所用到的filepath啦。在這裡和大家一起復習一下Android中建立資料夾時,所用到的獲取檔案儲存路徑的方法:
getFilesDir()路徑:/data/user/0/com.bobo.test/files
getDir("Bobo", Context.MODE_PRIVATE)路徑: /data/user/0/com.bobo.test/app_Bobo
getCacheDir()路徑: /data/user/0/com.bobo.test/cache
getDatabasePath()路徑: /data/user/0/com.bobo.test/databases/Bobo
getExternalCacheDir()路徑: /storage/emulated/0/Android/data/com.bobo.test/cache
getExternalFilesDir(null)路徑: /storage/emulated/0/Android/data/com.bobo.test/files
getExternalFilesDir("Bobo")路徑: /storage/emulated/0/Android/data/com.bobo.test/files/Bobo
Environment.getExternalStorageState()路徑: mounted //判斷有沒有掛載外部儲存卡
Environment.getDataDirectory()路徑: /data
Environment.getExternalStoragePublicDirectory("Bobo")路徑: /storage/emulated/0/Bobo
Environment.getDownloadCacheDirectory()路徑: /cache
Environment.getExternalStorageDirectory()路徑: /storage/emulated/0
Environment.getRootDirectory()路徑: /system
這些基本就是我們經常要用到的建立資料夾用到的獲取根目錄的方法了,在這裡我想說一下為什麼專案中要用getExternalCacheDir()這個方法,因為在這個目錄下存放的檔案都是隨著你APP的存在而存在,當你APP被解除安裝後,這些對應的檔案也會被刪除。另外這個目錄下的檔案,使用者可以通過設定->應用->應用詳情裡面的”清除快取“選項把他給清楚掉。現在的使用者會對隨便在sd卡下建立檔案非常的反感(我就是其中之一),所以建議大家建立檔案時使用:getExternalFilesDir()和getExternalCacheDir()方法。來存放你的檔案。
然後就是使用Intent來呼叫系統的裁剪方法,其中一些Intent的屬性已經在備註中有所描述,下面我對一些沒有加註釋的屬性做一些解釋:
new Intent("com.android.camera.action.CROP")呼叫系統裁剪的Action; intent.setDataAndType(uri,"image/*")設定裁剪的圖片型別,如果專案中有要求圖片的字尾名,可以使用image/png或者image/jpg來限制。對於output屬性和aspect屬性
圖片來源https://my.oschina.net/ryanhoo/blog/86843呵呵,偷偷截的圖,如果想對這些屬性有詳細的瞭解可以移步去看看。對於“return-data”的true和false的理解,當設定為true時:裁剪後的圖片會以Bitmap的形式返回到onActivityResult()的data中。可以通過data.getParcelable("data")得到,但是如果你最終要獲取的圖片非常大,那麼此方法會給你帶來麻煩,所以你要控制outputX和outputY保持在較小的尺寸。當設定為false時:你需要將MediaStore.EXTRA_OUTPUT關聯到一個Uri,此Uri是用來存放Bitmap的,此時,在onActivityResult()中的intent是獲取不到Bitmap的。呵呵,好了到此係統的裁剪就已經完成了。
最後是裁剪完成後獲取圖片的方法:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case PHOTO_REQUEST_TAKEPHOTO:// 當選擇拍照時呼叫 Uri uri=null; if(Build.VERSION.SDK_INT >= 24) { uri = FileProvider.getUriForFile(MainActivity.this,"com.bobo.test",tempFile); }else { uri = Uri.fromFile(tempFile); } startPhotoZoom(uri); break; case PHOTO_REQUEST_CUT:// 返回的結果 if(resultCode==RESULT_OK) { if (data != null) try { Bitmap bp = BitmapFactory.decodeStream(getContentResolver().openInputStream(cropImageUri)); iv_show.setImageBitmap(bp); } catch (FileNotFoundException e) { e.printStackTrace(); } } break; } }
最後奉上Github的連結(第一次往Github上傳專案,今天從申請賬號開始,到配置本地Git,再到Android Studio整合Git,上傳專案整體流程走了一遍,如果有不會這個的小夥伴也可以在評論區留下聯絡方式,一起探討哦):https://github.com/BoBoAndroid/TakePhotoZoomTest,好啦,結束!
最後再次感謝文章中提到的兩位大神對文章做的貢獻。