Android N。。。android
昨天把项目targetSdkVersion改为了26。问题接踵而来。bash
最严重的就是项目中有地方调用到了系统相机拍照功能,拍完返回图片一张。app
(Android中很多地方须要这样作的)有两种实现方法。其实这里的两种实现方法原理都是同样的。都是隐士Intent开启系统相机。拍完照后返回所拍摄的照片。ide
只不过两种方法返回的东西不同。ui
一种直接返回图片this
一种返回启动相机界面前指定的存储拍摄图片的Urispa
第一种方法:code
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE)
startActivityForResult(intent, TAKE_PHOTO_REQUEST)
复制代码
这里咱们只须要指定Intent的actioni就能够实现了。xml
能够在onActivityResult的回调中经过intent回传获取到图片对象。对象
Bitmap photo = intent.getParcelableExtra("data")复制代码
这样的图片对象回传不用想指定是没有第二种方法更为节省内存
项目中也是使用的第二种方法:
root_dir = Environment.getExternalStorageDirectory().toString() + File.separator + Constant.CACHE_PATH
pt_dir = root_dir + File.separator + "bike_operation.jpg"复制代码
先指定好图片要存储的路径。
下面先说一下N之前的操做。
你只须要以下:
val intentFromCapture = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
intentFromCapture.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1)
intentFromCapture.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(File(pt_dir)))startActivityForResult(intentFromCapture, Constant.PAIZHAO_REQUEST)
复制代码
经过Uri。fromFile指定一下图片存储路径对应的Uri
就能够在onActivityResult的回调中再次获取到这个Uri从而经过解析Uri拿到对应的文件路径。生成对应的Bitmap。
然而,由于昨天的targetSdkVersion改为了26在N设备上运行该代码的时候报了以下错误
android.os.FileUriExposedException: file:///storage/emulated/0/mangoebike_operation_cache/bike_damage.jpg exposed beyond app through ClipData.Item.getUri()
复制代码
文件Uri解析异常Google一下才晓得了就是7.0增长了更为严格的进程间文件数据共享的机制
Uri的获取方式不能再像往常同样获取了。须要以下作法
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.whxxcy.mango_operation.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
复制代码
清单application节点下面指定provider属性。authorities属性能够本身随意指定。可是要记得代码中待会儿还要用到它。这里咱们就以包名加.fileProvider.字段来指定。
再一个须要咱们指定的就是这个resource属性了。在res文件目录下新建xml文件夹再在文件夹中建立file_paths文件。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<paths>
<external-path
name="bike_operation"
path="mangoebike_operation_cache" />
</paths>
</resources>
复制代码
path属性在个人理解是用来拼接Uri的就是你不写它会在根目录中去寻找存放文件。
name属性必须指定。不指定编译通不过。在个人理解这个name属性实际上是你在代码中拍照生成的文件的名字。
指定完这两个属性来看代码:
val intentFromCapture = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
intentFromCapture.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val contentUri = FileProvider.getUriForFile(this@OperationActivity, packageName + ".fileProvider", File(pt_dir))
intentFromCapture.putExtra(MediaStore.EXTRA_OUTPUT, contentUri) //将拍取的照片保存到指定URI
} else {
intentFromCapture.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(File(pt_dir)))
}
startActivityForResult(intentFromCapture, Constant.PAIZHAO_REQUEST)复制代码
若是当前sdk版本大于等于24Uri的获取方式就变成
= FileProvider.getUriForFile(this@OperationActivity, packageName + ".fileProvider", File(pt_dir))复制代码
参数1: 上下文。参数2: 就是在provider中指定的authitrites。参数3:File对象一开始指定的存储拍摄照片的路径
而后在onActivityResult的回调中解析Uri获得Bitmap对象就能够啦。。。有描述不许确的地方后续再改正。。。。