【发布时间】:2019-11-16 04:08:01
【问题描述】:
这里是新的 Android Q Scoped Storage 的链接。
根据this Android Developers Best Practices Blog,storing shared media files(我的情况)应该使用MediaStore API 完成。
深入研究文档,我找不到相关功能。
这是我在 Kotlin 中的试用版:
val bitmap = getImageBitmap() // I have a bitmap from a function or callback or whatever
val name = "example.png" // I have a name
val picturesDirectory = getExternalFilesDir(Environment.DIRECTORY_PICTURES)!!
// Make sure the directory "Android/data/com.mypackage.etc/files/Pictures" exists
if (!picturesDirectory.exists()) {
picturesDirectory.mkdirs()
}
try {
val out = FileOutputStream(File(picturesDirectory, name))
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)
out.flush()
out.close()
} catch(e: Exception) {
// handle the error
}
结果是我的图像被保存在这里Android/data/com.mypackage.etc/files/Pictures/example.png,如最佳实践博客中所述Storing app-internal files
我的问题是:
如何使用 MediaStore API 保存图像?
Java 的答案同样可以接受。
提前致谢!
编辑
感谢 PerracoLabs
这真的很有帮助!
但还有 3 个点。
这是我的代码:
val name = "Myimage"
val relativeLocation = Environment.DIRECTORY_PICTURES + File.pathSeparator + "AppName"
val contentValues = ContentValues().apply {
put(MediaStore.Images.ImageColumns.DISPLAY_NAME, name)
put(MediaStore.MediaColumns.MIME_TYPE, "image/png")
// without this part causes "Failed to create new MediaStore record" exception to be invoked (uri is null below)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
put(MediaStore.Images.ImageColumns.RELATIVE_PATH, relativeLocation)
}
}
val contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
var stream: OutputStream? = null
var uri: Uri? = null
try {
uri = contentResolver.insert(contentUri, contentValues)
if (uri == null)
{
throw IOException("Failed to create new MediaStore record.")
}
stream = contentResolver.openOutputStream(uri)
if (stream == null)
{
throw IOException("Failed to get output stream.")
}
if (!bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream))
{
throw IOException("Failed to save bitmap.")
}
Snackbar.make(mCoordinator, R.string.image_saved_success, Snackbar.LENGTH_INDEFINITE).setAction("Open") {
val intent = Intent()
intent.type = "image/*"
intent.action = Intent.ACTION_VIEW
intent.data = contentUri
startActivity(Intent.createChooser(intent, "Select Gallery App"))
}.show()
} catch(e: IOException) {
if (uri != null)
{
contentResolver.delete(uri, null, null)
}
throw IOException(e)
}
finally {
stream?.close()
}
1- 保存的图片名称不正确“Myimage.png”
我尝试使用“Myimage”和“Myimage.PNG”,但都没有成功。
图像总是有一个由数字组成的名称,例如:
1563468625314.jpg
这给我们带来了第二个问题:
2- 即使我以png 格式压缩位图,图像仍保存为jpg。
不是什么大问题。只是好奇为什么。
3- 在低于 Android Q 的设备上,relativeLocation 位会导致异常。
加上“Android版本检查”if语句后,图片直接保存在Pictures文件夹的根目录下。
再一次谢谢你。
编辑 2
改为:
uri = contentResolver.insert(contentUri, contentValues)
if (uri == null)
{
throw IOException("Failed to create new MediaStore record.")
}
val cursor = contentResolver.query(uri, null, null, null, null)
DatabaseUtils.dumpCursor(cursor)
cursor!!.close()
stream = contentResolver.openOutputStream(uri)
这是日志
I/System.out: >>>>> Dumping cursor android.content.ContentResolver$CursorWrapperInner@76da9d1
I/System.out: 0 {
I/System.out: _id=25417
I/System.out: _data=/storage/emulated/0/Pictures/1563640732667.jpg
I/System.out: _size=null
I/System.out: _display_name=Myimage
I/System.out: mime_type=image/png
I/System.out: title=1563640732667
I/System.out: date_added=1563640732
I/System.out: is_hdr=null
I/System.out: date_modified=null
I/System.out: description=null
I/System.out: picasa_id=null
I/System.out: isprivate=null
I/System.out: latitude=null
I/System.out: longitude=null
I/System.out: datetaken=null
I/System.out: orientation=null
I/System.out: mini_thumb_magic=null
I/System.out: bucket_id=-1617409521
I/System.out: bucket_display_name=Pictures
I/System.out: width=null
I/System.out: height=null
I/System.out: is_hw_privacy=null
I/System.out: hw_voice_offset=null
I/System.out: is_hw_favorite=null
I/System.out: hw_image_refocus=null
I/System.out: album_sort_index=null
I/System.out: bucket_display_name_alias=null
I/System.out: is_hw_burst=0
I/System.out: hw_rectify_offset=null
I/System.out: special_file_type=0
I/System.out: special_file_offset=null
I/System.out: cam_perception=null
I/System.out: cam_exif_flag=null
I/System.out: }
I/System.out: <<<<<
我注意到 title 与名称匹配,所以我尝试添加:
put(MediaStore.Images.ImageColumns.TITLE, name)
它仍然没有工作,这是新的日志:
I/System.out: >>>>> Dumping cursor android.content.ContentResolver$CursorWrapperInner@51021a5
I/System.out: 0 {
I/System.out: _id=25418
I/System.out: _data=/storage/emulated/0/Pictures/1563640934803.jpg
I/System.out: _size=null
I/System.out: _display_name=Myimage
I/System.out: mime_type=image/png
I/System.out: title=Myimage
I/System.out: date_added=1563640934
I/System.out: is_hdr=null
I/System.out: date_modified=null
I/System.out: description=null
I/System.out: picasa_id=null
I/System.out: isprivate=null
I/System.out: latitude=null
I/System.out: longitude=null
I/System.out: datetaken=null
I/System.out: orientation=null
I/System.out: mini_thumb_magic=null
I/System.out: bucket_id=-1617409521
I/System.out: bucket_display_name=Pictures
I/System.out: width=null
I/System.out: height=null
I/System.out: is_hw_privacy=null
I/System.out: hw_voice_offset=null
I/System.out: is_hw_favorite=null
I/System.out: hw_image_refocus=null
I/System.out: album_sort_index=null
I/System.out: bucket_display_name_alias=null
I/System.out: is_hw_burst=0
I/System.out: hw_rectify_offset=null
I/System.out: special_file_type=0
I/System.out: special_file_offset=null
I/System.out: cam_perception=null
I/System.out: cam_exif_flag=null
I/System.out: }
I/System.out: <<<<<
而且我无法将date_added 更改为名称。
MediaStore.MediaColumns.DATA 已被弃用。
提前致谢!
【问题讨论】:
-
在我添加之前,我还在文件名中获取了这些随机数:
put(MediaStore.MediaColumns.DISPLAY_NAME, name + ".mp3") -
在这里查看我的答案stackoverflow.com/a/68110559/6039240
标签: java android image kotlin mediastore