最近自己在看这本书,看到这部分并亲手上机测试时,发现并不是照书上那样编码之后就能顺利打开相机拍照。经过思考和对比发现:
photoFile文件的转化uri部分编写的不合理。原因:如果运行设备的系统版本低于Android 7.0 ,调用Uri的formFile()方法将File对象转换成Uri对象;否则,就调用FIleProvider的getUriForFIle()方法将File对象转换成一个封装过的Uri对象。getUriForFIle()方法接收三个参数,第一个参数要求传入Context对象,第二个参数可以是任意唯一的字符串,第三个参数则是上面提到过的photoFile(File类型)对象。之所以要进行这样一层转换,是因为从Android 7.0 系统开始, 直接使用本地真实路径的Uri被认为是不安全的,会抛出一个FIleUriExposedException异常。而FileProvider是一种特殊的内容提供器, 它使用了和内容提供器类似的机制来对数据进行保护,可以选择性将封装过的Uri共享给外部, 从而提高了应用的安全性(上述这部分原因解释摘抄自第一行代码)。现改正如下:
第一步:在canTakePhoto的if语句判断中加入一个判断,从而决定获取Uri对象的转换方式,代码如下:
if(canTakePhoto){ if(Build.VERSION.SDK_INT >= 24){ imageUri = FileProvider.getUriForFile(mContext, BuildConfig.APPLICATION_ID + ".provider", mPhotoFile); }else{ imageUri = Uri.fromFile(mPhotoFile); } captureImage.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); }第二步:在AndroidManifest.xml中对内容提供器进行注册:
其中的provider节点是在application节点下,name属性的值是固定的, authorities属性的值和刚才getUriForFile()方法中的第二个参数一样。内部使用的<meta-data>来指定Uri的共享路径,并引用了一个@xml/file_paths资源。
<provider android:authorities="${applicationId}.provider" android:name="android.support.v4.content.FileProvider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"/> </provider>第三步:创建这个引用的资源。
res/xml/file_paths.xml文件
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external_files" path=""/> </paths>
经过上述修改之后就能打开相机并进行拍照。