总结Android调用系统相机拍照遇到的坑

来源:互联网 发布:java培训机构 知乎 编辑:程序博客网 时间:2024/05/16 15:12
拍照功能在应用开发中几乎已成为标配,例如用户通过拍照上传头像。实现拍照功能的方式有两种。第一种是使用相机API(即Camera类)来自定义拍照,第二种是使用Intent调用系统相机来拍照。其中最常见的方式是直接调用系统相机拍照来获取照片。

调用系统相机获取照片的流程如下,这里省去了声明权限和动态权限申请:
private String mFilePath;// 需要初始化,路径自定义private static final int REQUEST_CODE_CAMERA = 1;// 启动系统相机private void startCamareActivity() {    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);    intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.parse("file://" + mFilePath));    startActivityForResult(intent, REQUEST_CODE_CAMERA);}// 拿到照片@Overridepublic void onActivityResult(int requestCode, int resultCode, Intent data) {    if (requestCode == REQUEST_CODE_CAMERA && resultCode == RESULT_OK) {        // mFilePath即是拍照完成后的图片// 这里可以进入裁剪页面了    }}
通过Action为MediaStore.ACTION_IMAGE_CAPTURE的隐式Intent启动拍照,使用MediaStore.EXTRA_OUTPUT指定照片路径,成功返回后即可获取到照片的完整路径。

下面进入填坑阶段。

一.拍摄的照片被旋转了

明明在拍摄时照片是正的,进入裁剪页面发现照片竟然是被旋转的。这个现象在不同的设备上,表现会不一样,可能正常也可能被旋转,而且旋转的角度也不同。要解决这个问题,需要首选获取照片的旋转角度,再反转回去就可以了。

ExifInterface接口提供了多媒体文件比如JPG格式图片的一些附加信息,比如文件的旋转,gps,拍摄时间等。如下代码展示了使用ExifInterface获取图片的旋转角度。
/** * 获取图片的旋转角度 * @param path 图片的绝对路径 */private int getBitmapDegree(String imagePath) {    int degree = 0;    try {        // 从指定路径下读取图片,并获取其EXIF信息        ExifInterface exifInterface = new ExifInterface(imagePath);        // 获取图片的旋转信息        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;}

进行图形变换如旋转、缩放、移动的操作,可以使用Matrix类来完成。如下代码展示了使用Matrix对图片旋转,生成新的Bitmap。
/** * 将图片按照某个角度进行旋转 * @param bitmap 需要旋转的图片 * @param degree 旋转角度 */public static Bitmap rotateBitmapByDegree(Bitmap bitmap, int degree) {    Bitmap result = null;    // 根据旋转角度,生成旋转矩阵    Matrix matrix = new Matrix();    matrix.postRotate(degree);    try {        // 将原始图片按照旋转矩阵进行旋转,并得到新的图片        result = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);    } catch (Exception e) {    }    if (bitmap != null && !bitmap.isRecycled()) {        bitmap.recycle();bitmap = null;    }    return result;}

二.拍照完成后应用闪退

这个现象相对少见,目前在廉价的低端手机上出现过。启动拍照时正常,当在拍照界面点击确认按钮,拍照界面消失返回我们的应用时,直接闪退。更让人崩溃的是,Logcat里面没有相应的日志信息。无奈只能借助搜索,发现原来是手机厂商对系统做了修改(为了在低端硬件上能够运行Android系统...),当我们的应用程序的Activity启动拍照,进入系统相机时,我们的Activity被销毁了。这个情况在测试时也不是必现。测试机在使用一段时间后很容易出现,但如果将设备重启后开启我们的应用来拍照又没有问题(这是我们遇到的情况,可能不是必现规则)。

Activity被回收时保存数据,可以在onSaveInstanceState()生命周期方法中处理,将图片路径保存到Bundle中。
@Overrideprotected void onSaveInstanceState(Bundle outState) {    outState.putString("file_path", mFilePath);    super.onSaveInstanceState(outState);}

然后在onCreate()方法里,判断savedInstanceState不为空时,取出图片路径的值。
@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {    if (savedInstanceState != null) {        mFilePath = savedInstanceState.getString("file_path");// your code here    }}

网上看到另外一种恢复的方法。Activity没有重新创建,而是成员变量被回收了,当拍照返回时,在onActivityResult()方法中mFilePath为空。解决方法是从onRestoreInstanceState()方法恢复数据。这种情况暂时没遇到,做个记录。
@Overrideprotected void onRestoreInstanceState(Bundle savedInstanceState) {    if (TextUtils.isEmpty(mFilePath)) {        mFilePath = savedInstanceState.getString("file_path");    }    super.onRestoreInstanceState(savedInstanceState);}

0 0
原创粉丝点击