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

Android Q上用于辅助存储的媒体扫描器

轩辕远
2023-03-14

在更新的Android Q中,许多事情发生了变化,特别是作用域存储和file://URI的逐渐弃用。问题是缺乏关于如何在Android Q设备上正确处理媒体文件的文档。

我有一个媒体文件(音频)管理应用程序,但我还找不到一个可靠的方法告诉操作系统,我对一个文件执行了更改,以便它可以更新其纵隔记录。

选项1:MediaScannerService

MediaScannerConnection.scanFile(context, new String[]{ filePath }, new String[]{"audio/*"}, new MediaScannerConnection.OnScanCompletedListener() {
    @Override
    public void onScanCompleted(String s, Uri uri) {

    }
});
  • 与主存储中的文件://URI一起工作
  • 不能使用文件://来自辅助存储(如可移动存储)的URI
  • 不能使用任何内容://URI

选项2:广播

context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
  • 根本不工作
  • 很快被弃用

audiofileContentValuesmediastore.audio.audioColumns中的一些列值。

基于文件://URI的旧方法:

Uri uri = MediaStore.Audio.Media.getContentUriForPath(file_path);
newUri = context.getContentResolver().insert(uri, AudioFileContentValues);
  • mediastore.audio.media.GetContenturiforPath不推荐使用
  • 仍不工作

更新的方法基于我可以从文档中整理的内容:

Uri collection = MediaStore.Audio.Media.getContentUri(correctVolume);
newUri = context.getContentResolver().insert(collection, AudioFileContentValues);

其中,corretvolume将是来自主存储的external,而对于辅助存储,则类似于0000-0000,具体取决于文件所在的位置。

  • 插入返回内容URI,如content://media/external/audio/media/125,但对于位于主存储器中的文件,不在纵隔存储中持久化任何记录
  • 插入失败,没有返回URI,纵隔腔也没有记录

这些或多或少都是以前Android版本中可用的方法,但现在没有一种方法允许我通知系统我更改了一些音频文件元数据,并让Android更新MediaStore记录。事件尽管选项#1部分起作用,但这绝不可能是一个有价值的解决方案,因为它显然不支持内容URI。

在Android Q上有没有可靠的方法触发媒体扫描,尽管文件位于何处?根据Google的说法,我们甚至不应该关心文件位置,因为我们很快将只使用内容URI。纵隔在我看来一直有点令人沮丧,但现在的情况相当糟糕。

共有1个答案

邴姚石
2023-03-14

我现在也在纠结于这个问题。

我想你想做的事情一旦你上了Android Q,你就不能再做了,因为你不允许访问Q上的音乐目录,你只允许创建和访问你创建的目录中的文件。您没有创建音乐目录。

现在媒体的每一个变化都要发生,都要抛出纵隔。所以你预先插入你的音乐文件,然后从纵隔腔获得一个输出流来写入它。在介质上的Q上的所有更改都应该在纵隔室中完成,因此您将更改通知纵隔室甚至不会再发生了,因为您从来没有直接访问过该文件。

这有一个巨大的鱼子酱,所有的新东西在纵隔使这成为可能,并不存在于老版本的Android。所以我现在确实认为你将需要执行每件事两次,可悲的是。至少如果你想积极地影响你的音乐保存到哪里,那就是。

这两个纵隔柱在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版本的if检查中实现了两次。真烦人。我不想这么做。但这似乎是唯一的办法。

我将在这里放一些代码,说明我是如何在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
}

纵隔辅助器的方法是这样的

    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文件添加另一个.mp3。我现在没有默剧类型...所以我想我现在就去做吧。

这可能回答不了你所有的问题。对我来说肯定不是。但这是一个有帮助的开始,有一个粗略的想法,他们甚至改变了什么开始。

对于删除和更新文件,它在Q上是一样的。如果您对纵隔条目调用delete,该文件将被删除。以前,你必须手动删除文件也。但如果你在Q上这么做,你的应用程序就会崩溃。因此,您必须再次检查您是否使用了Q或较旧版本的android,并采取适当的行动。

 类似资料:
  • 我正在使用存储访问框架将图像下载到外部sd卡。问题是这些图像不会出现在图库中。我试图通过发送DocumentFile uri来通知Android媒体扫描仪使用意图,但这似乎不起作用。下面是我如何尝试通知媒体扫描器添加了新图像: 有没有其他方法来通知Android添加了新图像?(我已经尝试了这里描述的方法,但我无法使用这些方法获得真实路径)

  • 有人知道MSBuild的SonarQube扫描器是作为构建的一部分进行扫描并只将结果发回给SonarQube,还是EXE正在检测,我们可以将工件发送到Linux机器上的SonarQube进行分析,类似于使用sonar-scanner-cli扫描java工件的方式?

  • 我试图通过DownloadManager下载一张图片,并将其显示在Gallery应用程序中,但我所做的一切都不起作用。根据文档,我认为这段代码就足够了: 但是当文件下载时,它不会出现在Gallery应用程序中。所以我尝试了一个下载接收器来手动添加它,如下所示: 那也不行。打印有“filename”标记的URI类似于content://downloads/my_downloads/97'而不是下载的

  • 问题内容: Scanner.class 提供了许多有用的工具来分析数字,例如可以触发特定特征的 .hasNext ()和 .next_ _()方法。 在这样的某个地方,对于Date来说:第一次是要检测 String中的 日期,并根据格式调整响应( mm / dd / yy | dd / mm / yy | yyyymmdd ,是秒,是字母在里面,是四位数的年份,是负数…)。 编辑回应 扫描仪提供的

  • 本文向大家介绍Android中扫描多媒体文件操作详解,包括了Android中扫描多媒体文件操作详解的使用技巧和注意事项,需要的朋友参考一下 这篇文章从系统源代码分析,讲述如何将程序创建的多媒体文件加入系统的媒体库,如何从媒体库删除,以及大多数程序开发者经常遇到的无法添加到媒体库的问题等。本人将通过对源代码的分析,一一解释这些问题。 Android中的多媒体文件扫描机制 Android提供了一个很棒

  • 我找到了一些相关的答案,但没有一个能解释我是否真的需要Azure Media Services团队示例中的所有代码https://azure.microsoft.com/en-us/documentation/articles/media-services-copying-existing-blob/我只想把一个文件从blob上传到Azure Media Services。这样地: 但是我得到了