当前位置: 首页 > 知识库问答 >
问题:

媒体商店。Images.Media.insertImage已弃用

温亮
2023-03-14

我曾经使用< code>MediaStore保存图像。Images.Media.insertImage,但< code>insertImage方法现在已被否决。医生说:

此方法在 API 级别 29 中已弃用。应使用 MediaColumns#IS_PENDING 执行图像的插入,这样可以更丰富地控制生命周期。

我不太明白,因为<code>媒体列。IS_PENDING只是一个标志,我应该如何使用它?

我应该使用 ContentValues 吗

共有3个答案

夏景胜
2023-03-14

感谢您在步骤2:以Q样式保存图像时贡献iCantC。

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

e: java.lang.OutOfMemoryError: Java heap space

这是我使用的代码,因为我的用例是用于PNG图像,<code>位图的任何值。压缩小于100可能没有用处。以前的版本不适用于API 30,因此我将contentValues<code>RELATIVE_PATH

   
    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!!
    }

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

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)
    }

第4步:创建自定义FileProvider

package com.example.background.workers.provider

import androidx.core.content.FileProvider

class WorkerFileProvider : FileProvider() {

}

第五步:更新AndroidManifest.xml

更改自

<activity android:name=".MyActivity" />

<activity android:name=".MyActivity">
            <intent-filter>
                <action android:name="android.intent.action.PICK"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="android.intent.category.OPENABLE"/>
                <data android:mimeType="image/png"/>
            </intent-filter>
        </activity>
        <provider
            android:name=".workers.provider.WorkerFileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true"
            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>

步骤6:在xml下为FILE_PROVIDER_path添加一个资源

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="pictures" path="Pictures"/>
</paths>
慎弘化
2023-03-14

此方法在API级别29中已弃用。插入图像应使用MediaClons#IS_PENDING执行,它提供了对生命周期的更丰富控制。

要么我太笨了,无法理解文档,要么谷歌团队真的需要重构文档。

无论如何,从CommonsWare和coroutineDispatcher提供的链接发布完整的答案

步骤1:决定您的API级别

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)}
}

这应该让你滚!

耿永寿
2023-03-14

解决了的

@CommonsWare建议的代码没有任何问题,除非您使用< code>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)
            }
        }
 类似资料:
  • 我正在尝试获取uri和后解析为纵隔图像的路径。我这样做是为了获取URI: 在使用此函数之后,我转换路径中的uri: 但结果是,我有媒体存储的路径,但有第一个元素。例如:。但我只想要。 请不要告诉我使用连接和拆分,因为这不是我想要的。

  • 我试图在我的代码中使用Bodyparser,但代码被编辑器本身剪切,并表示Bodyparser已被弃用。我尝试了一些我在网上找到的替代代码,但都不起作用。附件是我正在使用的代码的截图。密码 代码:

  • 我想在谷歌地图上存储一些POI(兴趣点),只在android应用程序中使用 然后我想检索用户当前位置“x”km范围内的所有POI 所以,问题是:是否有可能将自定义数据存储在谷歌地图上供应用程序私人使用?(请提供任何示例的链接) 要存储的任何其他完全管理的解决方案

  • 我一直在研究这个问题,在提交我的代码后,7个案例通过了,然而,9个案例失败了。问题链接位于HackerRank:电子商店 问题陈述 一个女孩想买一个键盘和一个USB驱动器,她想尽可能多地花钱,但要在预算内(将这两个项目结合起来)。如果这两件物品的价格都超过了她的预算,那么退货-1,否则她就买不到了。强制性的是,她想买这两件东西,而不是一件。 例子 一系列键盘以数组的形式给出,USB驱动器以。现在,

  • URL release环境: https://skill.rokid.com/storev2