Android7.0中为了提高私有文件的安全性,对file:// Uri 类型的Uri做出了限制,导致一些APP的功能无法正常使用。前几天的一个头像裁剪问题被提上了日程,开始只是修改了拍照的Uri,忘记了还要裁剪
,因为直接使用的系统裁剪导致裁剪出了问题。下面贴出解决安卓7.0裁剪出问题的解决方案。首先拍照的解决在我以前的博客也有涉及,顺便打打广告:
一份完整的拍照后加水印代码
下面先贴出主要用到的方法,然后在解释里面的所涉及到的内容:
public void startPhotoZoom(Uri uri) {
File CropPhoto=new File(getExternalCacheDir(),"crop.jpg");
try{
if(CropPhoto.exists()){
CropPhoto.delete();
}
CropPhoto.createNewFile();
}catch(IOException e){
e.printStackTrace();
}
cropImageUri=Uri.fromFile(CropPhoto);
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/*");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //添加这一句表示对目标应用临时授权该Uri所代表的文件
}
// 下面这个crop=true是设置在开启的Intent中设置显示的VIEW可裁剪
intent.putExtra("crop", "true");
intent.putExtra("scale", true);
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
//输出的宽高
intent.putExtra("outputX", 300);
intent.putExtra("outputY", 300);
intent.putExtra("return-data", false);
intent.putExtra(MediaStore.EXTRA_OUTPUT, cropImageUri);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.putExtra("noFaceDetection", true); // no face detection
startActivityForResult(intent, PHOTO_REQUEST_CUT);
}
首先是Uri:对于Uri的理解这里不免会出现URI和Uri两种,首先URI位置在java.net.URI,显然是Java提供的一个类。而Uri位置在android.net.Uri,是由Android提供的一个类。通俗点理解就是:Uri是Android开发的,扩展了JAVA中URI的一些功能来特定的适用于Android开发,所以大家在开发时,只使用Android 提供的Uri即可;呵呵,有木有很清楚,如果想要对Uri和URI有更多的了解可以参考的博客,他的两篇文章对Uri的讲解非常的详细哦,我对Uri的理解也是从那学的
。
接下来涉及的好像就是创建文件夹所用到的filepath啦。在这里和大家一起复习一下Android中创建文件夹时,所用到的获取文件存储路径的方法:
getFilesDir()路径:/data/user/0/com.bobo.test/files
getDir("Bobo", Context.MODE_PRIVATE)路径: /data/user/0/com.bobo.test/app_Bobo
getCacheDir()路径: /data/user/0/com.bobo.test/cache
getDatabasePath()路径: /data/user/0/com.bobo.test/databases/Bobo
getExternalCacheDir()路径: /storage/emulated/0/Android/data/com.bobo.test/cache
getExternalFilesDir(null)路径: /storage/emulated/0/Android/data/com.bobo.test/files
getExternalFilesDir("Bobo")路径: /storage/emulated/0/Android/data/com.bobo.test/files/Bobo
Environment.getExternalStorageState()路径: mounted //判断有没有挂载外部存储卡
Environment.getDataDirectory()路径: /data
Environment.getExternalStoragePublicDirectory("Bobo")路径: /storage/emulated/0/Bobo
Environment.getDownloadCacheDirectory()路径: /cache
Environment.getExternalStorageDirectory()路径: /storage/emulated/0
Environment.getRootDirectory()路径: /system
这些基本就是我们经常要用到的创建文件夹用到的获取根目录的方法了,在这里我想说一下为什么项目中要用getExternalCacheDir()这个方法,因为在这个目录下存放的文件都是随着你APP的存在而存在,当你APP被卸载后,这些对应的文件也会被删除。另外这个目录下的文件,用户可以通过设置->应用->应用详情里面的”清除缓存“选项把他给清楚掉。现在的用户会对随便在sd卡下创建文件非常的反感(我就是其中之一),所以建议大家创建文件时使用:getExternalFilesDir()和getExternalCacheDir()方法。来存放你的文件。
然后就是使用Intent来调用系统的裁剪方法,其中一些Intent的属性已经在备注中有所描述,下面我对一些没有加注释的属性做一些解释:
new Intent("com.android.camera.action.CROP")调用系统裁剪的Action; intent.setDataAndType(uri,"image/*")设置裁剪的图片类型,如果项目中有要求图片的后缀名,可以使用image/png或者image/jpg来限制。对于output属性和aspect属性
图片来源呵呵,偷偷截的图,如果想对这些属性有详细的了解可以移步去看看
。对于“return-data”的true和false的理解,当设置为true时:裁剪后的图片会以Bitmap的形式返回到onActivityResult()的data中。可以通过data.getParcelable("data")得到,但是如果你最终要获取的图片非常大,那么此方法会给你带来麻烦,所以你要控制outputX和outputY保持在较小的尺寸。当设置为false时:你需要将MediaStore.EXTRA_OUTPUT关联到一个Uri,此Uri是用来存放Bitmap的,此时,在onActivityResult()中的intent是获取不到Bitmap的。呵呵,好了到此系统的裁剪就已经完成了。
最后是裁剪完成后获取图片的方法:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case PHOTO_REQUEST_TAKEPHOTO:// 当选择拍照时调用
Uri uri=null;
if(Build.VERSION.SDK_INT >= 24) {
uri = FileProvider.getUriForFile(MainActivity.this,"com.bobo.test",tempFile);
}else {
uri = Uri.fromFile(tempFile);
}
startPhotoZoom(uri);
break;
case PHOTO_REQUEST_CUT:// 返回的结果
if(resultCode==RESULT_OK) {
if (data != null)
try {
Bitmap bp = BitmapFactory.decodeStream(getContentResolver().openInputStream(cropImageUri));
iv_show.setImageBitmap(bp);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
break;
}
}
最后奉上Github的链接(第一次往Github上传项目,今天从申请账号开始,到配置本地Git,再到Android Studio集成Git,上传项目整体流程走了一遍,如果有不会这个的小伙伴也可以在评论区留下联系方式,一起探讨哦):https://github.com/BoBoAndroid/TakePhotoZoomTest,好啦,结束!
最后再次感谢文章中提到的两位大神对文章做的贡献。