礦坑一:android中調用相機拍照返回null的問題
很多的時候由於業務需求需要調用相機進行拍照,又由於國內手機ROM廠商眾多,各成一派。就會遇到拍照成功之后返回null的問題。
當然拍照失敗很可能是由於權限的原因或者硬件本身等其他的原因。
下面提供我用到的可以實現獲取到圖片信息的方法。基本的原理是先指定圖片的URI,相機根據URI地址去生成圖片,然后我們再讀取這張圖片的信息就OK了。不說了,直接上代碼吧!
private ArrayList<String> mImageList; private static final int REQUEST_CAMERA = 5; // 相機拍照標記 private static final int CAMERA_REQUEST_CODE = 1; /** * 拍照獲取照片 */ protected void selectPicFromCamera() { if (!SDCardUtils.isSDCardEnable()){ //不存在sd卡 Toast.makeText(this,R.string.sd_disable,Toast.LENGTH_SHORT).show(); return; } //android 6.0之后需要動態申請權限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.CAMERA}, CAMERA_REQUEST_CODE); } Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (cameraIntent.resolveActivity(this.getPackageManager()) != null) { tempFile = new File(FileUtils.createRootPath(this) + "/" + System.currentTimeMillis() + ".jpg"); LogUtils.e(tempFile.getAbsolutePath()); FileUtils.createFile(tempFile); Uri uri = FileProvider.getUriForFile(this, FileUtils.getApplicationId(this) + ".provider", tempFile); List<ResolveInfo> resInfoList = this.getPackageManager() .queryIntentActivities(cameraIntent, PackageManager.MATCH_DEFAULT_ONLY); for (ResolveInfo resolveInfo : resInfoList) { String packageName = resolveInfo.activityInfo.packageName; this.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION); } cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri); //Uri.fromFile(tempFile) startActivityForResult(cameraIntent, REQUEST_CAMERA); } else { Toast.makeText(this, "打開相機失敗", Toast.LENGTH_SHORT).show(); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_CAMERA && resultCode == RESULT_OK){ if (tempFile != null){ mImageList.add(tempFile.getAbsolutePath()); } } }
礦坑二:用戶拒絕相機的權限之后導致打開相機崩潰的問題
不同的廠商對與權限的管理也都是不一樣的,華為做的就比較好,必須的權限它會一直提示你授權,直到授權成功為止。被用戶禁止使用的權限,它也會進行本地推送通知,提醒用戶手動打開。
小米為發燒而生,它的系統確實是比較好適配的系統。嗯,手機確實會發燒,燙手。。。
比較坑的是魅族系統,被拒絕的權限不會有任何提示也不會發起再次申請權限。
我總結出來的解決辦法是在打開相機之前,先判斷一下相機是否可用,不可用的情況下先授權。
此方法針對魅族手機系統
/** * 是否有攝像頭權限 * * @return */ @SuppressLint("LongLogTag") @SuppressWarnings("deprecation") public static boolean hasCameraPermission() { // 無權限可能出現的情況(部分): // 1, 直接拋異常 // 2, 不拋異常,返回對象為空 // 3, 獲取到的數據為空 boolean canUse = true; Camera mCamera = null; try { mCamera = Camera.open(); mCamera.setParameters(mCamera.getParameters()); } catch (Exception e) { Log.e(TAG, "catch, 捕捉到異常, 無攝像頭權限"); // 1, 直接拋異常 canUse = false; if (mCamera != null) {// 返回對象非空(魅族) mCamera.release(); mCamera = null; Log.i(TAG, "catch, 對象非空,釋放資源"); } else if (mCamera == null) {// 2, 返回對象為空 Log.e(TAG, "catch, 對象為空"); } } finally { if (mCamera != null) { canUse = true; mCamera.release(); mCamera = null; Log.i(TAG, "finally, 對象非空,釋放資源"); } else if (mCamera == null) {// 2, 返回對象為空 canUse = false; Log.e(TAG, "finally, 對象為空"); } } Log.i(TAG, "返回"); return canUse; }
使用方法:
/** * 首先判斷相機是否可用,此問題針對魅族手機系統 * 如果相機權限被拒絕,則需要手動開啟 */ if (!hasCameraPermission()){ //開始手動打開權限 checkPremissionInterface.requestCameraPremission(); return; }
下面貼出手動打開系統的設置界面,手動授權的代碼:
public void requestCameraPremission() { new AppSettingsDialog .Builder(getActivity()) .setTitle("拍照權限") .setRationale("如果沒有請求的權限,此功能可能無法正常工作。打開應用程序設置以修改應用程序權限") .setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //取消按鈕事件,我這里是彈出fragment getFragmentManager().popBackStack(); } }) .build() .show(); }
礦坑三:寶寶難受,寶寶心里苦。產品非要在設置頭像的時候默認調用前置攝像頭進行拍照,我的天,我的天,於是出現的重大的bug。
之前一直都是用這斷代碼調用前置攝像頭,其中0代表后置攝像頭;1代表前置攝像頭;2代表外接攝像頭
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); cameraIntent.putExtra("android.intent.extras.CAMERA_FACING", 1);//這里試過值0,1,2 三星,華為均無效 startActivity(cameraIntent);
我使用三星Galaxy C9Pro 6.0.1,華為P9 EMUI 4.1 Android 6.0 無法調用前置攝像頭。其他OPPO R9 VIVIO X9 小米6 魅藍3s均可以正常調用前置攝像頭。
此時我的內心是崩潰的,從CSDN到博客園再到簡書都沒有找到對應的解決辦法。
於是開啟了自定義相機的不歸路。。。
三星機器拍照后獲取圖片的高寬發現,寬比高大,
11-03 14:18:04.726 4203-4203/bitmap.getHeight----->: 720
11-03 14:18:04.726 4203-4203/bitmap.getWidth----->: 1280
因此斷定拍照時圖片是旋轉過的,這是只需將得到的圖片旋轉90度即可得到正常的圖片
此時還有個問題就是前置攝像頭和后置攝像頭旋轉的角度是不一樣的,所以要注意這個問題,我是本地寫個變量記錄下當前的攝像頭是前置還是后置。
前置攝像頭拍出來的照片是左右翻轉的,所以我又進行了鏡像翻轉這個操作。
貼出我的代碼:
if (width < height) { bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight()); } else { if (cameraId == CameraKit.Constants.FACING_FRONT) { //前置攝像頭 Matrix matrix = new Matrix(); matrix.postRotate(-90);//逆時針轉90度 matrix.postScale(-1, 1); // 鏡像水平翻轉 bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); } else if (cameraId == CameraKit.Constants.FACING_BACK) { //后置攝像頭 Matrix matrix = new Matrix(); matrix.postRotate(90);//順時針轉90度 bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); } }