在Android7.0手机,用老方法调用系统相机拍照,一直抛,FileUriExposedException异常。这是因为,Android 7.0强制启用了被称作 StrictMode的策略,App对外无法暴露file://类型的URI了。用Intent携带这样的URI去打开外部App(比如:打开系统相机拍照),就会会抛出FileUriExposedException异常。官方给出FileProvider,解决方案。
具体使用如下步骤:
1、res目录下创建文件夹xml,并创建file_paths.xml文件,位置如下图:
xml文件名随意
xml文件内容如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--<files-path/> //代表的根目录: Context.getFilesDir()
<external-path/> //代表的根目录: Environment.getExternalStorageDirectory()
<cache-path/> //代表的根目录: getCacheDir()
<root-path/> //外置SD卡
-->
<external-path
name="external_files"
path="">
</external-path>
</resources>
2、Manifest.xml文件,application标签下:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.xxx.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/image_paths" />
</provider>
xxx内容随意,最好是包名,与其他项目不能重名
3、获取Uri方法:
private Uri getPhotoUri() {
Uri imageUri = null;
String sdDir = Environment.getExternalStorageDirectory().getAbsolutePath();
String fileName = "new_photo.jpg";
String path = sdDir + String.format("/%s/%s",
"AAAA", fileName);
File file = new File(path);
file.getParentFile().mkdirs();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
try {
imageUri = FileProvider.getUriForFile(this,
"com.xxx.fileprovider", file);
} catch (Exception e) {
e.printStackTrace();
}
} else {
imageUri = Uri.fromFile(file);
}
return imageUri;
}
4、系统相机调用方法:
private void jumpToTakePhoto() {
myUri = getPhotoUri();//myUri为全局Uri变量
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//拍照
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, getPhotoUri());
cameraIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//这里加入flag
startActivityForResult(cameraIntent, TAKEPHOTO_CODE);
}
5、申请权限并拍照:
private void getPermissionAndTakePhoto(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//Android版本大于6.0,动态申请权限
int checkCallPhonePermission = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
if (checkCallPhonePermission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]
{Manifest.permission.CAMERA//拍照权限
, Manifest.permission.WRITE_EXTERNAL_STORAGE//存储权限
}, REQUEST_CARME_STATE);
} else {
jumpToTakePhoto();//权限已经申请,直接拍照
}
} else {
jumpToTakePhoto();//Android版本小于6.0,,直接拍照
}
}
权限申请结果处理:
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == REQUEST_CARME_STATE && grantResults.length == 1 &&
grantResults[0] == PackageManager.PERMISSION_GRANTED) {
jumpToTakePhoto();//权限申请成功,去拍照
}
}
6、拍照完成后,返回展示:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Uri result=null;
if (TAKEPHOTO_CODE == requestCode) {
if (resultCode == RESULT_OK) {
try {
if(bitmap!=null){
bitmap.recycle();//回收,释放图片资源,否则再次拍摄会OOM异常
}
//拍照返回时,从路径获取文件转成Bitmap,并展示到imageView
bitmap= BitmapFactory.decodeStream(getContentResolver().openInputStream(getPhotoUri()));
imageView.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
}
上篇第一次做都是图片,有的地方图片不显示,好尴尬。。。