Android 7.0系统发布后,拿到能升级的nexus 6P,就开始了7.0的适配。发现Android7.0在修改头像时候进行拍照并裁剪图片时会出现photos app崩溃。仔细分析操作步骤和流程,发现照片拍照是成功的,SD卡也能保存相关的图片信息,但是在对拍照的图片进行裁剪时候出现了photos app崩溃;如下图:
同时发现通过选择相册进行选中图片后才进行裁剪就没有问题。看一下代码:
Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(Uri.fromFile(inputfile), IMAGE_UNSPECIFIED);//主要问题就在这个File Uri上面 ————代码语句A intent.putExtra("crop", "true"); intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); intent.putExtra("outputX", 180); intent.putExtra("outputY", 180); intent.putExtra("scale", true); intent.putExtra("return-data", false); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(outputfile));//定义输出的File Uri,之后根据这个Uri去拿裁剪好的图片信息 ————代码B intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); intent.putExtra("noFaceDetection", true); startActivityForResult(intent, RequestCode);
上网查找了一些资料都是说Android7.0后,发现Android7.0在这个方面最大变化就在于以前适用的File Uri需要更改为Content Uri,但是这个更改是需要编译的 targetSdkVersion 是24的时候才有效,我们的apptargetSdkVersion是23。所以问题上面的链接解决办法应该不是这个原因(这个解决在后文解决 targetSdkVersion=24 的时候需要用到);
但是从文章中知道了File Uri和Content Uri的区别,然后再去分析一下为什么从相册选择图片进行裁剪是生效的?通过代码分析和debug后发现,从相册选取图片得到的Uri是Content Uri而拍照后使用的是文件路径生成的File Uri,看来问题就是出在这里,并不是说我们app的targetSDKVersion不是24就可以使用File Uri,但是photos app的targetSdkVersion可能是24导致了它接受了File Uri而崩溃,那么我们需要做的就是把File Uri换成Content Uri。这里需要提的是,直接按照 这里的做法 去更换Content Uri并不能生效,会提示“Can not edit image under 50*50 pixels”的错误toast提示,其实是photos app找不到Content Uri传进去的图片文件。那么我们需要换一种方式去更换Content Uri,我们在 stackoverflow 上面找到更换Content Uri的方法,需要注意的是不是所有的File Uri都可以转换成Content Uri,应该是多媒体相关的文件才可以。下面是代码:
public static Uri getImageContentUri(Context context, File imageFile) { String filePath = imageFile.getAbsolutePath(); Cursor cursor = context.getContentResolver().query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[] { MediaStore.Images.Media._ID }, MediaStore.Images.Media.DATA + "=? ", new String[] { filePath }, null); if (cursor != null && cursor.moveToFirst()) { int id = cursor.getInt(cursor .getColumnIndex(MediaStore.MediaColumns._ID)); Uri baseUri = Uri.parse("content://media/external/images/media"); return Uri.withAppendedPath(baseUri, "" + id); } else { if (imageFile.exists()) { ContentValues values = new ContentValues(); values.put(MediaStore.Images.Media.DATA, filePath); return context.getContentResolver().insert( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); } else { return null; } } }
我们需要把上文第一处代码的Uri.fromFile(inputfile)更换成getImageContentUri生成的Uri。替换上去后运行程序试试,这样修改就可以了。
更进一步:要是我们把上文的代码,把app的targetSdkVersion改成24之后,在启动相机进行拍照时候,会发现这样的错误
android.os.FileUriExposedException: file:///storage/emulated/0/DCIM/Camera/TEMP_IMAGE1474468182889.jpg exposed beyond app through ClipData.Item.getUri();
不能拍照成功;使用FileProvider来产生Content Uri代替File Uri,按照上面网址介绍方法替换掉就可以;
然而我们在用FileProvider.getUriForFile替换掉所有的Uri.fromFile时候,可以拍照成功了,但是在剪裁图片时候还是会出现之前的“Can not edit image under 50*50 pixels”没有办法,只能把上文的代码语句A重新更改为getImageContentUri生成Content Uri,重新运行程序;这个时候可以拍照成功,进入图片裁剪photos app里面,但是裁剪完成Save的时候photos app又崩溃了:
应该是FileProvider的属性为android:exported="false"的原因,但是这里不能改为true(会报另一个错误:java.lang.RuntimeException: Unable to get provider android.support.v4.content.FileProvider: java.lang.SecurityException: Provider must not be exported)。
这个时候我们需要把代码语句B里面outputUri改为File Uri就可以了,最终的代码如下,调用相机拍照的代码自己替换成FileProvider就可以了:
Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(getImageContentUri(context , inputfile), IMAGE_UNSPECIFIED);//自己使用Content Uri替换File Uri intent.putExtra("crop", "true"); intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); intent.putExtra("outputX", 180); intent.putExtra("outputY", 180); intent.putExtra("scale", true); intent.putExtra("return-data", false); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(outputfile));//定义输出的File Uri intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); intent.putExtra("noFaceDetection", true); startActivityForResult(intent, RequestCode);
综上,我们完成了targetSdkVersion=24和小于24两种情况的图片裁剪适配;之后还是采用自己app内程序进行图片裁剪适配性比较好。
至于为什么Google需要对Content Uri和File Uri使用进行更改,应该是希望限制开发者对存储空间media文件的访问控制;
来自:http://www.jianshu.com/p/c73b959b6bcf
- 文章2300
- 用户1336
- 访客10862077
真正的成功是激励他人行动。
语法错误: 意外的令牌“标识符”
全面理解Gradle - 定义Task
Motrix全能下载工具 (支持 BT / 磁力链 / 百度网盘)
谷歌Pixel正在开始起飞?
获取ElementUI Table排序后的数据
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is
亲测!虚拟机VirtualBox安装MAC OS 10.12图文教程
华为手机app闪退重启界面清空log日志问题
android ndk开发之asm/page.h: not found
手机屏幕碎了怎么备份操作?
免ROOT实现模拟点击任意位置
新手必看修改DSDT教程
thinkpad t470p装黑苹果系统10.13.2