如何更新 Android Q 媒体商店中音频文件的元数据?
How to update metadata of audio file in Android Q media store?
更新媒体存储中音频文件的元数据在 Android Q OS 中不起作用,它在所有其他 OS.
中起作用
我正在使用 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});
对于AndroidQ设备,rowsUpdated始终为0,无一例外。
其他音乐播放器如何更新 Android Q 中的曲目元数据?
使用 Android Q 及以后你必须先获取文件
即
resolver.openInputStream(uri)?.use { stream -> outputFile.copyInputStreamToFile(stream) }
return outputFile.absolutePath
辅助函数
private fun File.copyInputStreamToFile(inputStream: InputStream?) {
this.outputStream().use { fileOut ->
inputStream?.copyTo(fileOut)
}
}
然后通过第三方修改元数据,我用的是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())
}
当文件由您的应用程序创建时,这工作正常
终于,花了一些时间,但我想通了。
首先,您需要获得对文件的访问权限。 Here you can read about that
接下来,我发现要更新标题或艺术家字段(也许其他人,我没有测试它们)你需要将列 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)
然后您可以编辑您需要的字段。同样要结束更新过程,请再次将 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)
所以在一个函数中,它看起来像这样:
@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)
}
它是用 Kotlin 编写的,但我想您会在 java 中弄清楚如何做到这一点。
更新
通过更新 MediaStore
,您不会更新任何 android 版本的真实文件。这意味着,如果一个文件被 MediaScannerConnection
扫描 and/or 更新(例如:重命名),您的更改将会丢失。 This answer 是对的。
我一直在通过 ContentResolver 更新 MediaStore 中的元数据,但这不再适用于 Android Q (API 29)。下面的代码给我一个警告,描述没有更新:
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DESCRIPTION, "Some text");
res = getContext().getContentResolver().update(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
values,
MediaStore.Images.Media._ID + "= ?", new String[]{sImageId});
android.process.media W/MediaProvider: Ignoring mutation of
description from com.example.android.someapp.app
这个媒体 post 描述了 how Google has changed the API for accessing and updating files,但是只更新 元数据 呢?警告似乎告诉我 Google 不再允许第三方应用程序使用 MediaStore,我也找到了警告的来源:
https://android.googlesource.com/platform/packages/providers/MediaProvider/+/master/src/com/android/providers/media/MediaProvider.java#2960
更新媒体存储中音频文件的元数据在 Android Q OS 中不起作用,它在所有其他 OS.
中起作用我正在使用 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});
对于AndroidQ设备,rowsUpdated始终为0,无一例外。 其他音乐播放器如何更新 Android Q 中的曲目元数据?
使用 Android Q 及以后你必须先获取文件
即
resolver.openInputStream(uri)?.use { stream -> outputFile.copyInputStreamToFile(stream) }
return outputFile.absolutePath
辅助函数
private fun File.copyInputStreamToFile(inputStream: InputStream?) {
this.outputStream().use { fileOut ->
inputStream?.copyTo(fileOut)
}
}
然后通过第三方修改元数据,我用的是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())
}
当文件由您的应用程序创建时,这工作正常
终于,花了一些时间,但我想通了。
首先,您需要获得对文件的访问权限。 Here you can read about that
接下来,我发现要更新标题或艺术家字段(也许其他人,我没有测试它们)你需要将列 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)
然后您可以编辑您需要的字段。同样要结束更新过程,请再次将 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)
所以在一个函数中,它看起来像这样:
@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)
}
它是用 Kotlin 编写的,但我想您会在 java 中弄清楚如何做到这一点。
更新
通过更新 MediaStore
,您不会更新任何 android 版本的真实文件。这意味着,如果一个文件被 MediaScannerConnection
扫描 and/or 更新(例如:重命名),您的更改将会丢失。 This answer 是对的。
我一直在通过 ContentResolver 更新 MediaStore 中的元数据,但这不再适用于 Android Q (API 29)。下面的代码给我一个警告,描述没有更新:
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DESCRIPTION, "Some text");
res = getContext().getContentResolver().update(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
values,
MediaStore.Images.Media._ID + "= ?", new String[]{sImageId});
android.process.media W/MediaProvider: Ignoring mutation of description from com.example.android.someapp.app
这个媒体 post 描述了 how Google has changed the API for accessing and updating files,但是只更新 元数据 呢?警告似乎告诉我 Google 不再允许第三方应用程序使用 MediaStore,我也找到了警告的来源: https://android.googlesource.com/platform/packages/providers/MediaProvider/+/master/src/com/android/providers/media/MediaProvider.java#2960