如何更新 Android Q 媒体商店中音频文件的元数据?

Vel*_*elu 6 android mediastore android-music-player android-contentprovider android-10.0

更新媒体商店中音频文件的元数据不适用于 Android Q 操作系统,它适用于所有其他操作系统。

我正在使用 uri 指定为 MediaStore.Audio.Media.EXTERNAL_CONTENT_URI 的内容提供程序。它在所有低于 Android Q 的设备上运行良好。下面是我用来更新轨道元数据的代码。

ContentValues cv = new ContentValues();
ContentResolver resolver = getContentResolver();
Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;

cv.put(MediaStore.Audio.Media.TITLE, newTitle);
cv.put(MediaStore.Audio.Media.ALBUM, newAlbumName);
cv.put(MediaStore.Audio.Media.ARTIST, newArtistName);

int rowsUpdated = resolver.update(uri, cv, 
MediaStore.Audio.Media._ID + " = ? ", new String[]{audioId});
Run Code Online (Sandbox Code Playgroud)

对于 Android Q 设备,rowsUpdated 始终为 0,无一例外。其他音乐播放器如何更新 Android Q 中的曲目元数据?

Kin*_*ine 11

最后,花了一些时间,但我想通了。

首先,您需要获得对文件的访问权限。在这里你可以读到

接下来,我发现要更新标题或艺术家字段(可能是其他的,我没有测试它们)您需要将列MediaStore.Audio.Media.IS_PENDING值设置为 1。就像这样:

    val id = //Your audio file id

    val values = ContentValues()
    values.put(MediaStore.Audio.Media.IS_PENDING, 1)

    val uri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id)
    contentResolver.update(uri, values, null, null)
Run Code Online (Sandbox Code Playgroud)

然后您可以编辑您需要的字段。还要结束MediaStore.Audio.Media.IS_PENDING再次设置为 0的更新过程:

    val id = //Your audio file id
    val title = //New title
    val artist = //New artist

    val values = ContentValues()
    values.put(MediaStore.Audio.Media.IS_PENDING, 0)
    values.put(MediaStore.Audio.Media.TITLE, title)
    values.put(MediaStore.Audio.Media.ARTIST, artist)

    val uri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id)
    contentResolver.update(uri, values, null, null)
Run Code Online (Sandbox Code Playgroud)

所以在一个函数中,它看起来像这样:

    @RequiresApi(value = android.os.Build.VERSION_CODES.Q)
    fun updateMetadata(contentResolver: ContentResolver, id: Long, title: String, artist: String) {
        val uri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id)
        val values = ContentValues()

        values.put(MediaStore.Audio.Media.IS_PENDING, 1)
        contentResolver.update(uri, values, null, null)

        values.clear()
        values.put(MediaStore.Audio.Media.IS_PENDING, 0)
        values.put(MediaStore.Audio.Media.TITLE, title)
        values.put(MediaStore.Audio.Media.ARTIST, artist)
        contentResolver.update(uri, values, null, null)
    }
Run Code Online (Sandbox Code Playgroud)

它是用 Kotlin 编写的,但我想你会弄清楚如何用 Java 来做到这一点。

UPD

通过更新,MediaStore您不会在任何 android 版本中更新真实文件。这意味着,如果文件将被更新(例如:重命名)和/或被MediaScannerConnection您的更改扫描将丢失。这个答案是对的。


And*_*ass 5

使用 Android Q 及更高版本,您必须首先获取文件

IE

resolver.openInputStream(uri)?.use { stream -> outputFile.copyInputStreamToFile(stream) }
return outputFile.absolutePath
Run Code Online (Sandbox Code Playgroud)

辅助功能

private fun File.copyInputStreamToFile(inputStream: InputStream?) {
    this.outputStream().use { fileOut ->
        inputStream?.copyTo(fileOut)
    }
}
Run Code Online (Sandbox Code Playgroud)

然后通过第三方更改元数据,我使用 J Audio Tagger

然后覆盖旧文件

// From https://developer.android.com/reference/android/content/ContentProvider
// String: Access mode for the file. May be
// "r" for read-only access,
// "w" for write-only access (erasing whatever data is currently in the file),
// "wa" for write-only access to append to any existing data,
// "rw" for read and write access on any existing data, and
// "rwt" for read and write access that truncates any existing file. This value must never be null.

mContext.application.contentResolver.openOutputStream(uri, "w")?.use { stream ->
            stream.write(file.readBytes())
        }
Run Code Online (Sandbox Code Playgroud)

当文件是由您的应用程序创建时,这可以正常工作