Android 11使用MediaStore保存插入图片

Android 11使用MediaStore保存插入图片

自己写的app是保存和浏览插画的,保存就涉及到几个需求,而又要适配android 10,android11,记录一下,顺便给刚好需要适配的踩踩坑,我踩过的大家就不要再踩一遍了。

我的需求

  • 需要能用byte array保存图片
  • 需要能根据图片名称或者相对路径判断出这张图是否保存过
  • 需要显示在相册
  • 尽量不要申请WRITE_EXTERNAL_STORAGE

实现

插入

fun Context.save(byteArray: ByteArray, name: String) {
     
    val values = ContentValues();
    values.put(MediaStore.MediaColumns.DISPLAY_NAME, name.split("/").last())
    values.put(MediaStore.MediaColumns.MIME_TYPE, if (name.endsWith("png")) {
     
        "image/png"
    } else {
     
        "image/jpeg"
    })

    val path = if (name.contains("/")) {
     
        "${
       Environment.DIRECTORY_PICTURES}/PixEz/${name.split("/").first()}"
    } else {
     
        "${
       Environment.DIRECTORY_PICTURES}/PixEz"
    }
    values.put(MediaStore.MediaColumns.RELATIVE_PATH, path);
    var uri: Uri? = null
    var outputStream: OutputStream? = null
    try {
     
        uri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
        outputStream = contentResolver.openOutputStream(uri!!)!!
        outputStream.write(byteArray)
        outputStream.flush()
        outputStream.close()
    } catch (e: Exception) {
     
        if (uri != null) {
     
            contentResolver.delete(uri, null, null);
        }
    } finally {
     
        outputStream?.close()
    }
}

这边在建立相册里的文件夹,子文件夹都测试过,没有问题,也不需要请求权限,算是实现了第一个、第三个和第四个需求
那么,剩下需要能根据图片名称或者相对路径判断出这张图是否保存过
是否存在:

fun Context.exist(name: String): Boolean {
     
    val projection = arrayOf(
            MediaStore.Images.Media._ID,
    )
    val path = if (name.contains("/")) {
     
        "${
       Environment.DIRECTORY_PICTURES}/PixEz/${name.split("/").first()}"
    } else {
     
        "${
       Environment.DIRECTORY_PICTURES}/PixEz"
    }
    //想不到吧?居然是这样写?
    //咕噜咕噜,这不翻源码写的出来?
    val selection = "${
       MediaStore.Images.Media.RELATIVE_PATH} LIKE ? AND ${
       MediaStore.Images.Media.DISPLAY_NAME} = ?"
    val selectionArgs = arrayOf(
            "%${
       path}%",
            name.split("/").last(),
    )
    val sortOrder = "${
       MediaStore.Images.Media.DISPLAY_NAME} ASC"
    val query = contentResolver.query(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            projection,
            selection,
            selectionArgs,
            sortOrder
    )
    query?.use {
      cursor ->
        while (cursor.moveToNext()) {
     
            return true
        }
    }
    return false
}

这里两个坑,第一个,如果是=不是like,是匹配不到的,path也需要加上%,
第二个坑,如果你需要限制limit 1,这个在android Q是会直接报异常退出的
上面的方法就能够判断出相对路径下的图片是否已存在

这里又出现问题了

你会发现,这种方法判断exist,只对是由MediaStore保存的图片好使,传统模式啊,SAF啊,通通查不到
那么怎么解决呢?申请WRITE_EXTERNAL_STORAGE ,本地的图片就都能查到了
???
这个疑问就得交给google了,这个MediaStore不是为了改善滥用权限到处存文件的问题吗?怎么到头来还是需要申请储存权限?那我用File一把梭不香吗?防君子不防小人?

MediaStore适合什么场景

我觉得,适合无视重复存图的场景,其他场景可以选择SAF或者传统File
顺便SAF适配起来文档也稀烂,写起来拼接路径也很糟糕,还会遇到国产系统选择就闪退的问题
搞得新的这几个这么麻烦,难怪开发者跟进不积极

你可能感兴趣的:(Android,java,android,java)