Android图片Android之做人不缺爱

MIUI 系统 BUG,Android 调用相机崩溃?将拍照适配

2017-07-25  本文已影响1427人  nanchen2251

写在前面

昨天也是为大家分享了 7.0 相机适配,今天就来为大家讲讲 Android 之相机适配。

提起 Android 调用系统相机拍照上传图片或者是显示图片,想必任何一位开发 Android 的朋友都不会陌生,基本这个功能已经涵盖各个应用了,今天,我就来给大家聊聊网上并不多见却有经常听到大家吐槽的问题。

根据相机适配对图片的操作,所以有了这款图片压缩库:[https://github.com/nanchen2251/CompressHelper

拍照功能实现

对于拍照功能的实现方式我这里就不多谈了,无非两种,一种是利用相机的 API 来自定义相机,另一种是利用 Intent 调用系统指定的相机拍照。而这两种方式的实现网上搜索一大把,我就不在这里啰嗦了。

有没有相机可用?

前面讲到我们是调用系统指定的相机 APP 来拍照,那么系统是否存在可以被我们调用的 APP 呢?这个我们不敢确定,毕竟 Android 奇葩问题多,还真有遇到过这种极端的情况导致闪退的。虽然很极端,但作为客户端人员还是要进行处理,方式有二:

try-catch 这种粗暴的方式大家肯定很熟悉了,那么要如何检测系统有没有相机 APP 可用呢?系统在 PackageManager 里为我们提供这样一个 API:


通过这样一个 API ,可以知道系统是否存在 Action 为 MediaStore.ACTION_IMAGE_CAPTURE 的 Intent 可以唤起的拍照界面,具体实现代码如下:

/**
     * 判断系统中是否存在可以启动的相机应用
     *
     * @return 存在返回true,不存在返回false
     */
    public boolean hasCamera() {
        PackageManager packageManager = mActivity.getPackageManager();
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        List<ResolveInfo> list = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
        return list.size() > 0;
    }

拍出来的照片“歪了”!!!

经常会遇到一种情况,拍照时看到照片是正的,但是当我们的 APP 获取到这张照片时,却发现旋转了 90 度(也有可能是 180、270,不过 90 度比较多见,貌似都是由于手机传感器导致的)。很多童鞋对此感到很困扰,因为不是所有手机都会出现这种情况,就算会是出现这种情况的手机上,也并非每次必现。要怎么解决这个问题呢?从解决的思路上看,只要获取到照片旋转的角度,利用 Matrix 来进行角度纠正即可。那么问题来了,要怎么知道照片旋转的角度呢?细心的童鞋可能会发现,拍完一张照片去到相册点击属性查看,能看到下面这样一堆关于照片的属性数据。


图片原来的宽高居然都是 -1 ,真是奇葩了!难怪,inSampleSize 经过处理之后结果还是 1 。狠狠的吐槽了之后,总是要回来解决问题的。那么,图片的宽高信息都丢失了,我去哪里找啊? 像下面这样?
public static Bitmap decodeBitmapFromFile(String imagePath, int requestWidth, int requestHeight) {
            ...
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;//不加载图片到内存,仅获得图片宽高
            Bitmap bitmap = BitmapFactory.decodeFile(imagePath, options);
            bitmap.getWidth();
            bitmap.getHeight();
            ...
        } else {
            return null;
        }
    }

no,此方案行不通,inJustDecodeBounds = true 时,BitmapFactory 获得 Bitmap 对象是 null;
那要怎样才能获图片的宽高呢?前面提到的 ExifInterface 再次帮了我们大忙,通过它的下面两个属性即可拿到图片真正的宽高。


顺手吐槽一下,为什么高不是 TAG_IMAGE_HEIGHT 而是 TAG_IMAGE_LENGTH。改良过后的代码实现如下:
public static Bitmap decodeBitmapFromFile(String imagePath, int requestWidth, int requestHeight) {
       if (!TextUtils.isEmpty(imagePath)) {
           Log.i(TAG, "requestWidth: " + requestWidth);
           Log.i(TAG, "requestHeight: " + requestHeight);
           if (requestWidth <= 0 || requestHeight <= 0) {
               Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
               return bitmap;
           }
           BitmapFactory.Options options = new BitmapFactory.Options();
           options.inJustDecodeBounds = true;//不加载图片到内存,仅获得图片宽高
           BitmapFactory.decodeFile(imagePath, options);
           Log.i(TAG, "original height: " + options.outHeight);
           Log.i(TAG, "original width: " + options.outWidth);
           if (options.outHeight == -1 || options.outWidth == -1) {
               try {
                   ExifInterface exifInterface = new ExifInterface(imagePath);
                   int height = exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, ExifInterface.ORIENTATION_NORMAL);//获取图片的高度
                   int width = exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, ExifInterface.ORIENTATION_NORMAL);//获取图片的宽度
                   Log.i(TAG, "exif height: " + height);
                   Log.i(TAG, "exif width: " + width);
                   options.outWidth = width;
                   options.outHeight = height;
               } catch (IOException e) {
                   e.printStackTrace();
               }
           }
           options.inSampleSize = calculateInSampleSize(options, requestWidth, requestHeight); //计算获取新的采样率
           Log.i(TAG, "inSampleSize: " + options.inSampleSize);
           options.inJustDecodeBounds = false;
           return BitmapFactory.decodeFile(imagePath, options);

       } else {
           return null;
       }
   }

再看一下,打印出来的 log


以上总结了这么些身边童鞋经常问起,但网上又不多见的适配问题,希望可以帮到一些开发童鞋少走弯路。文中多次提到小米的机子,并不代表只有MIUI上有这样的问题存在,仅仅只是因为我身边带的几部机子大都是小米的。对待适配问题,在搜索引擎都无法提供多少有效的信息时,我们只能靠断点、打 log、观察控制台的日志、以及 API 文档来寻找一些蛛丝马迹作为突破口,相信办法总比困难多。
以上内容采自:There
至于为什么基本全文 copy,是因为我觉得作者已经讲的特别清楚了,我没必要做二次重复,也只是给大家分享一下。
那下面就让我来补充一下不一样的开发情景。

如果同事写好了压缩九宫格显示图片呢?

这时候你们大框架已经搞定了,只需要你传回一个文件的path,你可能会这样写:(下面所有代码都在 onActivityResult()` 方法)

if (null != imageGridAdapter.uri) {
    final String url = PhotoUtil.getImageUrlFromActivityResult(this, imageGridAdapter.uri);//这个方法可以拿到图片的path
    Log.e(TAG, "onActivityResult: url:" + url);
    if (!TextUtils.isEmpty(url)) {
        file = new File(url);
        size = file.length();
        Log.e(TAG, "onActivityResult: size:" + size);
        if (size > 0 ){
          ImageItem imageItem = new ImageItem();
          imageItem.ImageId = ImageItem.NEW_ID;
          imageItem.PhotoPath = url;
          imageGridAdapter.getmDataList().add(imageItem);
          imageGridAdapter.notifyDataSetChanged();
          imageGridAdapter.uri = null;
        }
  }
}

好像没啥问题呀,拿到图片的 path,new 一个文件,如果文件 size = 0,则不显示,大于 0 说明图片存在,则显示图片,提示 UI 刷新。
嗯,的确,绝大部分手机都测试通过了,然而在坑爹的部分MIUI系统上出现了,返回 size 为 0,进不到判断循环,自然不会显示那个图片。
这时候肯定要到 google 上去搜上一圈,一圈下来收获不少,却没找到真正解决的办法。
这里有位朋友就说啦,这个 size 为0,但是间隔一定的时间就可以 new 出 size 不为 0 的 file,而这个时间是不固定的。


做不完的开源,写不完的矫情。欢迎扫描下方二维码或者公众号搜索「nanchen」关注我的微信公众号,目前多运营 Android ,尽自己所能为你提升。如果你喜欢,为我点赞分享吧~


nanchen
上一篇 下一篇

猜你喜欢

热点阅读