You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在MediaStore扫描到的音频文件同目录下创建新音频文件?

如何在MediaStore扫描到的音频文件同目录下创建新音频文件?

老哥我太懂你这糟心的情况了!之前我做音频裁剪工具的时候也踩过一模一样的坑——用Media3 Transformer把裁剪好的音频存到原歌曲目录了,结果刷新App的时候MediaStore死活不认这个新文件,还时不时蹦个NullPointerException出来,非得手动重启App或者去文件管理器里戳一下才正常。给你唠唠我后来搞定的办法:

一、先搞对保存路径的获取(适配Scoped Storage)

Android 10及以上用了Scoped Storage,不能直接硬写文件路径了,得从原音频的MediaStore数据里拿合法的存储位置:

  • 从你查到的原音频Uri,用ContentResolver查它的RELATIVE_PATH列,这个就是它在外部存储的相对路径(比如Music/MyCollection/),这就是咱们要存新文件的父目录。
  • 先给新音频在MediaStore里插个条目,这样MediaStore从一开始就知道有这个文件,后续查询不会空:
val contentValues = ContentValues().apply {
    put(MediaStore.Audio.Media.DISPLAY_NAME, "剪好的-${原文件名}.mp3") // 自定义新文件名
    put(MediaStore.Audio.Media.MIME_TYPE, "audio/mpeg") // 格式要对应,比如flac就改audio/flac
    put(MediaStore.Audio.Media.RELATIVE_PATH, 原音频的RELATIVE_PATH) // 用刚才查到的原目录路径
    put(MediaStore.Audio.Media.IS_PENDING, 1) // 标记为待写入,避免MediaStore提前扫描
}
// 插入后拿到可写的Uri,后续用这个Uri给Media3写文件
val newAudioUri = contentResolver.insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, contentValues)

二、用Media3 Transformer写入到MediaStore Uri

别再直接写文件路径了,就用上面拿到的newAudioUri让Media3写入,这样写入和MediaStore索引同步:

val transformer = Transformer.Builder(context)
    .setDataSourceFactory(DefaultDataSource.Factory(context))
    .build()

// 构建裁剪请求,替换成你自己的起始、结束时间
val editRequest = MediaItemEditRequest.Builder(原音频的MediaItem)
    .setTrim(裁剪开始时间毫秒值, 裁剪结束时间毫秒值)
    .build()

// 执行裁剪并写入到MediaStore的Uri
transformer.edit(editRequest, newAudioUri)
    .addListener({
        // 写入成功后,把IS_PENDING改成0,让MediaStore正式索引这个文件
        contentValues.clear()
        contentValues.put(MediaStore.Audio.Media.IS_PENDING, 0)
        newAudioUri?.let { uri ->
            contentResolver.update(uri, contentValues, null, null)
        }
        // 这时候再刷新MediaStore查询,肯定能拿到新文件信息,不会NPE了
    }, Executors.newSingleThreadExecutor())

三、如果已经直接写了文件,怎么补救

要是你之前已经硬写了文件到原目录,那得手动通知MediaScanner扫描这个新文件,不然MediaStore不知道它存在,查的时候就返回null炸NPE:

// 替换成你实际的新文件绝对路径
val newFilePath = "/storage/emulated/0/Music/MyCollection/剪好的歌曲.mp3"
MediaScannerConnection.scanFile(
    context,
    arrayOf(newFilePath),
    arrayOf("audio/mpeg") // 对应你的音频MIME类型
) { path, uri ->
    // 扫描完成后,这里能拿到新文件的MediaStore Uri,之后查询就没问题了
}

为啥会碰NPE?

说白了就是你写完文件后,MediaStore还没来得及扫描索引这个新文件,你就急着去查询,结果查到的是null,直接用就炸了。要么在写入前就通过MediaStore创建条目,要么写完后主动触发扫描,等扫描完再刷新数据。

对了,权限别忘了!Android 13+要申请READ_MEDIA_AUDIO和WRITE_MEDIA_AUDIO,低版本可能需要WRITE_EXTERNAL_STORAGE,但尽量用MediaStore的方式,少要全存储权限,合规性更好。

备注:内容来源于stack exchange,提问作者Vanja Vujovic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.13 17:10:29