Android MediaStore.Images.Media.insertImage已弃用

Android MediaStore.Images.Media.insertImage已弃用,android,mediastore,Android,Mediastore,我以前使用MediaStore.images.Media.insertImage保存图像,但insertImage方法现在已不推荐使用。他们说: 此方法在API级别29中被弃用。应插入图像 可以使用,这提供了更丰富的 对生命周期的控制 我真的不明白,因为MediaColumns.u PENDING只是一个标志,我应该如何使用它 我应该使用ContentValues 解决 @commonware中建议的代码没有问题,但如果您使用targetSdkVersion 29编程,则必须添加以下条件: va

我以前使用
MediaStore.images.Media.insertImage
保存图像,但
insertImage
方法现在已不推荐使用。他们说:

此方法在API级别29中被弃用。应插入图像 可以使用,这提供了更丰富的 对生命周期的控制

我真的不明白,因为
MediaColumns.u PENDING
只是一个标志,我应该如何使用它

我应该使用
ContentValues

解决

@commonware中建议的代码没有问题,但如果您使用
targetSdkVersion 29
编程,则必须添加以下条件:

val contentValues = ContentValues().apply {
            put(MediaStore.MediaColumns.DISPLAY_NAME, System.currentTimeMillis().toString())
            put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { //this one
                put(MediaStore.MediaColumns.RELATIVE_PATH, relativeLocation)
                put(MediaStore.MediaColumns.IS_PENDING, 1)
            }
        }
此方法在API级别29中被弃用。应插入图像 使用MediaColumns#IS_PENDING执行,这提供了更丰富的 对生命周期的控制

要么我太傻了,不懂文档,要么谷歌团队真的需要重构文档

无论如何,发布由和提供的完整答案

第1步:决定您的API级别

步骤2:Q样式保存图像

第3步:如果未启用Q以传统样式保存图像

这会让你兴奋的

感谢您在上的贡献 步骤2:以Q样式保存图像

我在Android Studio中遇到了一些内存使用问题,我不得不打开Sublime进行修复。要修复此错误,请执行以下操作:

e:java.lang.OutOfMemoryError:java堆空间
这是我使用的代码,因为我的用例用于PNG图像,
bitmap.compress的任何值小于100都可能没有用处。
以前的版本在API 30上不起作用,所以我将contentValues
相对路径更新为
目录\u DCIM
contentResolver.insert(外部内容URI,


private val dateFormatter=SimpleDateFormat(
“yyyy.MM.dd”位于“HH:MM:ss z”,Locale.getDefault()
)
private val legacyOrQ:(位图)->Uri={if(Build.VERSION.SDK\u INT>=Build.VERSION\u code.Q)
saveImageInQ(it)else legacySave(it)}
private fun saveImageInQ(位图:位图):Uri{
val filename=“${dateFormatter.format(Date())}.png的${title}u”
输出流?
val contentValues=contentValues()。应用{
put(显示名称、文件名)
put(MIME_类型,“图像/png”)
put(相对路径、目录\u DCIM)
put(正在挂起,1)
}
//使用应用程序上下文获取contentResolver
val contentResolver=applicationContext.contentResolver
val uri=contentResolver.insert(外部内容uri,contentValues)
uri?.let{contentResolver.openOutputStream(it)}。也{fos=it}
fos?使用{bitmap.compress(bitmap.CompressFormat.PNG,100,it)}
fos?.flush()
fos?.close()
contentValues.clear()
contentValues.put(正在挂起,0)
乌里?让我来{
update(it,contentValues,null,null)
}
返回uri!!
}
步骤3:如果不在Q上,则以传统样式保存图像

private-fun-legacySave(位图:位图):Uri{
val appContext=applicationContext
val filename=“${dateFormatter.format(Date())}.png的${title}u”
val directory=getExternalStoragePublicDirectory(目录图片)
val file=file(目录,文件名)
val outStream=FileOutputStream(文件)
compress(bitmap.CompressFormat.PNG,100,扩展)
溢流
流出。关闭()
MediaScannerConnection.scanFile(appContext,arrayOf(file.absolutePath),
空,空)
返回FileProvider.getUriForFile(appContext,${appContext.packageName}.provider“,
文件)
}
步骤4:创建自定义文件提供程序

package com.example.background.workers.provider
导入androidx.core.content.FileProvider
类WorkerFileProvider:FileProvider(){
}
步骤5:更新您的AndroidManifest.xml

改变



步骤6:在xml下为文件提供程序路径添加资源 在我的情况下,我需要图片文件夹


我正在添加第二个答案,因为我不确定是否有人关心版本检查,但如果您执行了他们的步骤,嗯。。。 从

步骤5:更新您的AndroidManifest.xml

改变


使用
ContentValues
调用
insert()
带有
的项被设置为
0
。请参见示例,尽管在我的示例中,我保存的是视频,而不是图像。问题:这段代码中发生了什么:
uri?。让{resolver.openOutputStream(uri)?。使用{outputStream->val sink=Okio.buffer(Okio.sink(outputStream))response.body()?.source()?.let{sink.writeAll(it)}sink.close()}
在我的情况下,我正在从URL下载视频到设备。
response.body().source()
给我一个Okio
source
表示我正在下载的视频字节。
Okio.buffer(Okio.sink(outputStream))
给我一个Okio
Sink
表示我将字节写入的位置,以及
writeAll()
wri
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) saveImageInQ(imageBitMap)
    else saveImageInLegacy(imageBitMap)

//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(uri, values, null, null)
          
          return imageUri
 
    }
//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)}

}

<activity android:name=".MyActivity" />
        <activity android:name=".legacy.LegacyMyActivity"/>
        <activity android:name=".MyActivity" />
        <provider
            android:name=".workers.provider.WorkerFileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true"
            android:enabled="@bool/atMostKitkat"
            android:permission="android.permission.MANAGE_DOCUMENTS">
            <intent-filter>
                <action android:name="android.content.action.DOCUMENTS_PROVIDER"/>
            </intent-filter>
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths"/>
        </provider>
        <activity-alias android:name=".legacy.LegacyMyActivity"
            android:targetActivity=".MyActivity"
            android:enabled="@bool/atMostJellyBeanMR2">
            <intent-filter>
                <action android:name="android.intent.action.PICK" />
                <category android:name="android.intent.category.OPENABLE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="image/png" />
            </intent-filter>
        </activity-alias>