矿坑一: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); } }