随着更新的Android Q的出现,许多事情发生了变化,尤其是在范围存储和file:///
URI逐渐弃用的情况下。问题在于缺少有关如何在Android Q设备上正确处理媒体文件的文档。
我有一个媒体文件(音频)管理应用程序,但找不到一种可靠的方法来告诉OS我对文件进行了更改,以便它可以更新其MediaStore记录。
选项1:MediaScannerService
MediaScannerConnection.scanFile(context, new String[]{ filePath }, new String[]{"audio/*"}, new MediaScannerConnection.OnScanCompletedListener() {
@Override
public void onScanCompleted(String s, Uri uri) {
}
});
file://
URI file://
URI content://
URI 选项2:广播
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
选项3:手动插入MediaStore
AudioFileContentValues
是MediaStore.Audio.AudioColumns
中的某些列值。
基于file://
URI的旧方法:
Uri uri = MediaStore.Audio.Media.getContentUriForPath(file_path);
newUri = context.getContentResolver().insert(uri, AudioFileContentValues);
MediaStore.Audio.Media.getContentUriForPath
已弃用基于我可以从documentation总结的新方法:
Uri collection = MediaStore.Audio.Media.getContentUri(correctVolume);
newUri = context.getContentResolver().insert(collection, AudioFileContentValues);
correctVolume
将位于主存储中的external
,而二级存储则类似于0000-0000
,具体取决于文件所在的位置。
content://media/external/audio/media/125
,但MediaStore中没有记录保留在主存储中的文件这些或多或少是早期Android版本中可用的所有方法,但是现在它们都不能让我通知系统我更改了一些音频文件元数据,并让Android更新MediaStore记录。尽管选项1可以部分起作用,但由于它显然不支持内容URI,所以这永远不是一个有价值的解决方案。
尽管文件位于何处,是否有可靠的方法可以触发Android Q上的媒体扫描?据Google称,我们甚至不必在乎文件的位置,因为我们很快将只使用内容URI。在我看来,MediaStore一直让人有些沮丧,但是现在情况变得更糟了。
答案 0 :(得分:0)
我目前也在为此而苦苦挣扎。
我认为一旦您在Android Q上,您想做的事无法再做一次,因为不允许您访问Q上的音乐目录。仅允许您在创建的目录中创建和访问文件。您尚未创建音乐目录。
现在,必须对Media进行所有更改,否则将MediaStore丢掉了。因此,您需要事先插入音乐文件,然后从MediaStore获取输出流以对其进行写入。对Media on Q的所有更改都应该扔到MediaStore上,因此您通知MediaStore更改也不再发生了,因为您从未直接访问文件。
它有一个巨大的鱼子酱,因为MediaStore中所有使之成为可能的新事物在旧版本的Android中都不存在。因此,我目前确实相信,不幸的是,您将需要两次实施所有操作。至少如果您想积极影响音乐的保存位置。
这两个MediaStore列在Q中是新的,并且在Q之前不存在,您可能需要在Q中使用
MediaStore.Audio.Media.RELATIVE_PATH
,您可以影响它的保存路径。因此,我将“ Music / MyAppName / MyLibraryName”放在此处,最终将“ song.mp3”保存到“ Music / MyAppName / MyLibraryName / song.mp3”中MediaStore.Audio.Media.IS_PENDING
,您应该在仍在编写歌曲的同时将其设置为1,然后再将其更新为0。我现在也开始对两次Android版本检查是否实现了。它很烦人。我不想做但这似乎是唯一的方法。
我只想在这里介绍一些如何在Android.Q及以下版本上插入音乐的代码。这不是完美的。我必须为Q指定MIME类型,因为flacs现在会以某种方式变为.flac.mp3,因为它似乎并没有得到它。
因此,无论如何,这是我已经更新以与Q一起使用的一部分,并且之前,它会从NAS上的音乐播放器下载音乐文件。该应用程序是用Kotlin编写的,不确定是否对您有问题。
override fun execute(library : Library, remoteApi: RemoteApi, ctx: Context) : Boolean {
var success = false
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val values = ContentValues().apply {
put(MediaStore.Audio.Media.RELATIVE_PATH, library.rootFolderRelativePath)
put(MediaStore.Audio.Media.DISPLAY_NAME, remoteLibraryEntry.getFilename())
put(MediaStore.Audio.Media.IS_PENDING, 1)
}
val collection = MediaStore.Audio.Media
.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
val uri = ctx.contentResolver.insert(collection, values)
ctx.contentResolver.openOutputStream(uri!!).use {
success = remoteApi.downloadMusic(remoteLibraryEntry, it!!)
}
if(success) {
values.clear()
val songId = JDrop.mediaHelper.getSongId(uri)
JDrop.db.music.insert(Music(mediaStoreId = songId, remoteId = remoteLibraryEntry.remoteId, libraryId = library.id))
values.put(MediaStore.Audio.Media.IS_PENDING, 0)
ctx.contentResolver.update(uri, values, null, null)
} else {
ctx.contentResolver.delete(uri, null, null)
}
} else {
val file = File("${library.rootFolderPublicDirectory}/${remoteLibraryEntry.getFilename()}")
if(file.exists()) file.delete()
success = remoteApi.downloadMusic(remoteLibraryEntry, file.outputStream())
if (success) {
MediaScannerConnection.scanFile(ctx, arrayOf(file.path), arrayOf("audio/*")) { _, uri ->
val songId = JDrop.mediaHelper.getSongId(uri)
JDrop.db.music.insert(Music(mediaStoreId = songId, remoteId = remoteLibraryEntry.remoteId, libraryId = library.id))
}
}
}
return success
}
MediaStoreHelper方法在这里
fun getSongId(uri : Uri) : Long {
val cursor = resolver.query(uri, arrayOf(Media._ID), null, null, null)
return if(cursor != null && cursor.moveToNext()) {
val idIndex = cursor.getColumnIndex(Media._ID)
val id = cursor.getLong(idIndex)
cursor.close()
id
} else {
cursor?.close()
-1
}
}
一件事,当您不指定MIME类型时,似乎会认为mp3是MIME类型。因此,.flac文件将另存为name.flac.mp3,因为如果没有文件,它会添加mp3文件类型,并且会认为它是mp3。它不会为mp3文件添加另一个.mp3。我想我现在什么地方都没有MIME类型...所以我现在就继续做。
还有一个有用的Google IO讨论范围/共享存储https://youtu.be/3EtBw5s9iRY
那可能不会回答您所有的问题。确实足够不适合我。但这是一个有用的开始,让我们大致了解他们一开始所做的更改。
如果在媒体存储条目上调用delete,则删除和更新文件的种类与Q相同,该文件将被删除。之前,您还必须手动删除该文件。但是,如果您在Q上执行此操作,则您的应用将崩溃。因此,您必须再次检查是否在Q或更旧版本的android上,然后采取适当的措施。