Android  N。。。

昨天把项目targetSdkVersion改成了26。问题接踵而来。

最严重的就是项目中有地方调用到了系统相机拍照功能,拍完返回图片一张。

(Android中不少地方需要这样做的)有两种实现方法。其实这里的两种实现方法原理都是一样的。都是隐士Intent开启系统相机。拍完照后返回所拍摄的照片。

只不过两种方法返回的东西不一样。

一种直接返回图片

一种返回启动相机界面前指定的存储拍摄图片的Uri

第一种方法:

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE)
                startActivityForResult(intent, TAKE_PHOTO_REQUEST)
复制代码

这里我们只需要指定Intent的actioni就可以实现了。

可以在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对象就可以啦。。。有描述不准确的地方后续再改正。。。。