search
尋找貓咪~QQ 地點 桃園市桃園區 Taoyuan , Taoyuan

Android 調用系統功能實現圖片選擇器,你可能會遇到的問題匯總

【Android 應用開發】(61)
作者同類文章X

版權聲明:本文為博主原創文章,未經博主允許不得轉載。

圖片選擇器在手機應用中屢見不鮮,設置頭像、聊天傳圖等常見類似場景都需要使用。為了保持不同設備上體驗的一致性和較好的兼容性,比較穩妥的做法是在應用內自實現相機拍照、相冊選圖和圖片裁剪功能。但是,這個實現過程比較複雜,費時費力。更多時候,或者說在項目初期,我們都會選擇直接調用系統提供的這些功能來完成一個圖片選擇器。然而,由於安卓設備的多樣性,總會遇到各種各樣的兼容問題。本文就來總結總結,調用系統相機、相冊和裁剪功能實現圖片選擇器的過程中,我們需要注意的一些地方。

示例代碼

這裡簡單使用一個示例代碼,演示調用系統相機或相冊,獲取圖片,然後使用系統裁剪功能處理圖片,並顯示到一個 ImageButton 視圖裡面:

publicclassMainActivityextendsFragmentActivity {publicstaticfinalint REQUEST_CAMERA = 1; publicstaticfinalint REQUEST_ALBUM = 2; publicstaticfinalint REQUEST_CROP = 3; publicstaticfinal String IMAGE_UNSPECIFIED = "image/*"; private ImageButton mPictureIb; private File mImageFile; @OverrideprotectedvoidonCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mPictureIb = (ImageButton) findViewById(R.id.ib_picture); } publicvoidonClickPicker(View v) { new AlertDialog.Builder(this) .setTitle("選擇照片") .setItems(new String{"拍照", "相冊"}, new OnClickListener { @OverridepublicvoidonClick(DialogInterface dialogInterface, int i) { if (i == 0) { selectCamera; } else { selectAlbum; } } }) .create .show; } privatevoidselectCamera { createImageFile; if (!mImageFile.exists) { return; } Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mImageFile)); startActivityForResult(cameraIntent, REQUEST_CAMERA); } privatevoidselectAlbum { Intent albumIntent = new Intent(Intent.ACTION_PICK); albumIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_UNSPECIFIED); startActivityForResult(albumIntent, REQUEST_ALBUM); } privatevoidcropImage(Uri uri){ Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(uri, IMAGE_UNSPECIFIED); intent.putExtra("crop", "true"); intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mImageFile)); startActivityForResult(intent, REQUEST_CROP); } privatevoidcreateImageFile { mImageFile = new File(Environment.getExternalStorageDirectory, System.currentTimeMillis + ".jpg"); try { mImageFile.createNewFile; } catch (IOException e) { e.printStackTrace; Toast.makeText(this, "出錯啦", Toast.LENGTH_SHORT).show; } } @OverrideprotectedvoidonActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (RESULT_OK != resultCode) { return; } switch (requestCode) { case REQUEST_CAMERA: cropImage(Uri.fromFile(mImageFile)); break; case REQUEST_ALBUM: createImageFile; ifreturn; } Uri uri = data.getData; if (uri != null) { cropImage(uri); } break; case REQUEST_CROP: mPictureIb.setImageURI(Uri.fromFile(mImageFile)); break; } } }

效果如圖(不同設備,系統功能呈現有所不同):

看似完美,你以為上述代碼就能結束了的話,那就大錯特錯啦!這裡面還有一些兼容問題要處理,還有一些地方需要特殊說明。

拍照圖片存儲問題

Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mImageFile)); startActivityForResult(cameraIntent, REQUEST_CAMERA);

其中

MediaStore.EXTRA_OUTPUT

數據表示,拍照所得圖片保存到指定目錄下的文件(一般會在 SD 卡中創建當前應用的目錄,並創建臨時文件保存圖片)。然後,在 onActivityResult 方法中根據文件路徑獲取圖片。

如果不為 intent 添加該數據的話,將在 onActivityResult 的 intent 對象中返回一個 Bitmap 對象,通過如下代碼獲取:

Bitmap bmp = data.getParcelableExtra("data");

值得注意的是,這裡的 Bitmap 對象是拍照所得圖片的一個

縮略圖

,尺寸很小!系統這麼做也是充分考慮到應用的內存佔用問題。試想一下,如今手機設備中高清相機拍出來的照片,一張圖的大小高達十幾兆,如果返回這麼大的圖片,內存佔用相當嚴重,何況很多時候知識臨時使用而已。所以,調用系統相機時,一般都會添加參數,避免返回 Bitmap 對象。當然,這麼做也能保證應用產生的數據,包括文件,都能存儲在應用目錄下,方便清理緩存時統一清除。

部分手機,比如三星手機,調用系統相機拍照所得的照片可能會發生自動旋轉問題,常見為旋轉 90°。所以,要求我們在拍照之後,使用圖片之前,判斷圖片是否發生過旋轉,如果是,要將照片旋轉回來。

這是獲取圖片旋轉角度的代碼:

/** * 獲取圖片旋轉角度 * @param path 圖片路徑 * @return */privateintparseImageDegree(String path) { int degree = 0; try { ExifInterface exifInterface = new ExifInterface(path); int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); switch (orientation) { case ExifInterface.ORIENTATION_ROTATE_90: degree = 90; break; case ExifInterface.ORIENTATION_ROTATE_180: degree = 180; break; case ExifInterface.ORIENTATION_ROTATE_270: degree = 270; break; } } catch (IOException e) { e.printStackTrace; } return degree; }

這是根據指定角度旋轉圖片的代碼:

/** * 圖片旋轉操作 * * @param bm 需要旋轉的圖片 * @param degree 旋轉角度 * @return 旋轉后的圖片 */private Bitmap rotateBitmap(Bitmap bm, int degree) { Bitmap returnBm = null; Matrix matrix = new Matrix; matrix.postRotate(degree); try { returnBm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth, bm.getHeight, matrix, true); } catch (OutOfMemoryError e) { } if (returnBm == null) { returnBm = bm; } if (bm != returnBm) { bm.recycle; } return returnBm; }

橫豎屏切換問題

在部分手機,調用系統拍照功能時,可能會發生橫豎屏切換過程,導致返回應用時當前 Activity 發生銷毀重建,各個生命周期又重新走了一遍。此時,一些應用內的變數數據可能丟失,使用時容易發生空值異常,進而導致 app 崩潰退出。

為了避免這種現象,我們需要在 AndroidManifest.xml 文件的對應 標籤中添加屬性:

這樣,當發生屏幕旋轉時,不會導致 Activity 銷毀重建,而是執行

onConfigurationChanged

方法:

@OverridepublicvoidonConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); }Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(uri, IMAGE_UNSPECIFIED); intent.putExtra("crop", "true"); intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mImageFile)); startActivityForResult(intent, REQUEST_CROP);

可以看出,調用系統裁剪功能,需要設置一些 Extra 參數,很多人容易在這裡產生疑惑,不知如何取捨,如何設值。這裡列舉一下常用的 Extra 名字、值類型和作用:



熱門推薦

本文由 yidianzixun 提供 原文連結

寵物協尋 相信 終究能找到回家的路
寫了7763篇文章,獲得2次喜歡
留言回覆
回覆
精彩推薦