Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 859|回复: 0

android中调用相机拍照返回null的问题的终极解决办法

[复制链接]
  • TA的每日心情
    奋斗
    昨天 12:49
  • 签到天数: 789 天

    [LV.10]以坛为家III

    2049

    主题

    2107

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    722638
    发表于 2021-6-30 13:05:35 | 显示全部楼层 |阅读模式

     

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

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-9-7 03:35 , Processed in 2.073872 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表