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适配起来文档也稀烂,写起来拼接路径也很糟糕,还会遇到国产系统选择就闪退的问题
搞得新的这几个这么麻烦,难怪开发者跟进不积极