if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) saveImageInQ(imageBitMap)
else saveImageInLegacy(imageBitMap)
步骤2:以Q样式保存图像
//Make sure to call this function on a worker thread, else it will block main thread
fun saveImageInQ(bitmap: Bitmap):Uri {
val filename = "IMG_${System.currentTimeMillis()}.jpg"
var fos: OutputStream? = null
val imageUri: Uri? = null
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg")
put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
put(MediaStore.Video.Media.IS_PENDING, 1)
}
//use application context to get contentResolver
val contentResolver = application.contentResolver
contentResolver.also { resolver ->
imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
fos = imageUri?.let { resolver.openOutputStream(it) }
}
fos?.use { bitmap.compress(Bitmap.CompressFormat.JPEG, 70, it) }
contentValues.clear()
contentValues.put(MediaStore.Video.Media.IS_PENDING, 0)
resolver.update(imageUri, contentValues, null, null)
return imageUri
}
步骤3:如果未启用Q以旧样式保存图像
//Make sure to call this function on a worker thread, else it will block main thread
fun saveTheImageLegacyStyle(bitmap:Bitmap){
val imagesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
val image = File(imagesDir, filename)
fos = FileOutputStream(image)
fos?.use {bitmap.compress(Bitmap.CompressFormat.JPEG, 100, it)}
}
Thanks for contributing iCantC on Step 2: Save the image in Q style. I ran into some issues with memory usage in Android Studio, which I had to open Sublime to fix. To fix this error:
e: java.lang.OutOfMemoryError: Java heap space
This is the code I used as my use case is for PNG images, any value of bitmap.compress less than 100 is likely not useful. Previous version would not work on API 30 so I updated contentValues RELATIVE_PATH to DIRECTORY_DCIM also contentResolver.insert(EXTERNAL_CONTENT_URI, ...
private val dateFormatter = SimpleDateFormat(
"yyyy.MM.dd 'at' HH:mm:ss z", Locale.getDefault()
)
private val legacyOrQ: (Bitmap) -> Uri = { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
saveImageInQ(it) else legacySave(it) }
private fun saveImageInQ(bitmap: Bitmap): Uri {
val filename = "${title}_of_${dateFormatter.format(Date())}.png"
val fos: OutputStream?
val contentValues = ContentValues().apply {
put(DISPLAY_NAME, filename)
put(MIME_TYPE, "image/png")
put(RELATIVE_PATH, DIRECTORY_DCIM)
put(IS_PENDING, 1)
}
//use application context to get contentResolver
val contentResolver = applicationContext.contentResolver
val uri = contentResolver.insert(EXTERNAL_CONTENT_URI, contentValues)
uri?.let { contentResolver.openOutputStream(it) }.also { fos = it }
fos?.use { bitmap.compress(Bitmap.CompressFormat.PNG, 100, it) }
fos?.flush()
fos?.close()
contentValues.clear()
contentValues.put(IS_PENDING, 0)
uri?.let {
contentResolver.update(it, contentValues, null, null)
}
return uri!!
}
Step 3: If not on Q save the image in legacy style
private fun legacySave(bitmap: Bitmap): Uri {
val appContext = applicationContext
val filename = "${title}_of_${dateFormatter.format(Date())}.png"
val directory = getExternalStoragePublicDirectory(DIRECTORY_PICTURES)
val file = File(directory, filename)
val outStream = FileOutputStream(file)
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outStream)
outStream.flush()
outStream.close()
MediaScannerConnection.scanFile(appContext, arrayOf(file.absolutePath),
null, null)
return FileProvider.getUriForFile(appContext, "${appContext.packageName}.provider",
file)
}
Step 4: Create a custom FileProvider
package com.example.background.workers.provider
import androidx.core.content.FileProvider
class WorkerFileProvider : FileProvider() {
}
5条答案
按热度按时间vxf3dgd41#
已解决
@CommonsWare建议的代码没有问题,只是如果您使用
targetSdkVersion 29
编程,则必须添加条件:r9f1avp52#
此方法在API级别29中已弃用。应使用MediaColumns#IS_PENDING执行图像插入,它可对生命周期提供更丰富的控制。
要么是我太笨了,看不懂这些文档,要么是Google团队真的需要重构文档。
无论如何,从CommonsWare和coroutineDispatcher提供的链接发布完整的答案
**步骤1:**确定您所处的API级别
步骤2:以Q样式保存图像
步骤3:如果未启用Q以旧样式保存图像
这应该能让你爽起来!
hyrbngr73#
Thanks for contributing iCantC on Step 2: Save the image in Q style.
I ran into some issues with memory usage in Android Studio, which I had to open Sublime to fix. To fix this error:
This is the code I used as my use case is for PNG images, any value of
bitmap.compress
less than 100 is likely not useful. Previous version would not work on API 30 so I updated contentValuesRELATIVE_PATH
toDIRECTORY_DCIM
alsocontentResolver.insert(EXTERNAL_CONTENT_URI, ...
Step 3: If not on Q save the image in legacy style
Step 4: Create a custom FileProvider
step 5: update your AndroidManifest.xml
changes from
to
step 6: add a resource under xml for FILE_PROVIDER_PATHS in my case I needed the pictures folder
vaj7vani4#
所有答案的总和,以及每个答案的重构版本。
如果您的应用已使用文件提供程序,则可以跳过对
AndroidManifest.xml
和filepaths.xml
的添加。更新(2022年12月)
我不得不用
applicationContext.getExternalFilesDir(DIRECTORY_PICTURES)
替换getExternalStoragePublicDirectory(DIRECTORY_PICTURES)
,因为它在早期版本的Android中似乎会崩溃。请确保您在filepaths.xml
中提供了根目录。保存为PNG
保存为JPG格式
机器人清单. xml
资源/文件路径. xml
导入(以防遗漏)
nzrxty8p5#
我添加了第二个答案,因为我不确定是否有人关心版本检查,但如果你这样做,他们是更多的步骤,嗯...从
步骤5:更新您AndroidManifest.xml
更改自
至
步骤6:在xml下为FILE_PROVIDER_PATHS添加资源与我之前的答案相同
步骤7:在res/values下为bool.xml添加资源
第8步:在res/values-v19下执行另一步
第9步:最后,如果您需要查看已保存的文件,则重要更改为
actionView.addFlags(FLAG_GRANT_READ_URI_PERMISSION)