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

MediaStore.Audio.Media.DATA返回无效路径致setDataSource异常求助

问题分析与解决方案

我来帮你梳理下问题根源和解决办法:

为什么会出现这个异常?

  1. MediaStore数据不同步:当音频文件被第三方应用删除、SD卡移除或用户手动删除后,系统的MediaStore数据库不会立刻同步更新,导致你从Cursor中拿到的DATA字段指向了一个已经不存在的文件。
  2. DATA字段已废弃:从Android Q(API 29)开始,MediaStore.Audio.Media.DATA就被标记为废弃,直接依赖这个字段获取路径的方式在高版本系统中会越来越不可靠。
  3. 存储权限限制:即使你申请了存储权限,在Android 10+的分区存储机制下,直接访问文件路径也可能遇到隐性权限问题,触发setDataSource的参数异常。

具体解决方案

1. 紧急修复:先检查文件是否存在

在调用setDataSource前,先判断文件真实存在性,避免抛出异常:

String thisPath = cursor.getString(pathColumn);
File audioFile = new File(thisPath);
Bitmap bitmap = null;

if (audioFile.exists() && audioFile.isFile()) {
    MediaMetadataRetriever mmr = new MediaMetadataRetriever();
    try {
        mmr.setDataSource(thisPath);
        byte[] data = mmr.getEmbeddedPicture();
        if (data != null) {
            bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
        }
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
        bitmap = null;
    } finally {
        mmr.release(); // 必须释放资源,避免内存泄漏
    }
} else {
    // 文件不存在,跳过当前条目
    bitmap = null;
}
songList.add(new Song(thisId, thisTitle, thisArtist, thisAlbum, bitmap));

2. 长期适配:改用Content Uri访问媒体文件

这是Android官方推荐的方式,既避免路径失效问题,又能适配高版本分区存储:

ContentResolver contentResolver = getContentResolver();
Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Cursor cursor = contentResolver.query(uri, null, null, null, null);

if (cursor != null && cursor.moveToFirst()) {
    // 获取必要字段的索引
    int idColumn = cursor.getColumnIndex(MediaStore.Audio.Media._ID);
    int titleColumn = cursor.getColumnIndex(MediaStore.Audio.Media.TITLE);
    int artistColumn = cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST);
    int albumColumn = cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM);

    do {
        long audioId = cursor.getLong(idColumn);
        // 通过音频ID构建Content Uri
        Uri audioUri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, audioId);
        String thisTitle = cursor.getString(titleColumn);
        String thisArtist = cursor.getString(artistColumn);
        String thisAlbum = cursor.getString(albumColumn);
        Bitmap bitmap = null;

        MediaMetadataRetriever mmr = new MediaMetadataRetriever();
        try {
            // 使用Content Uri和ContentResolver设置数据源
            mmr.setDataSource(this, audioUri);
            byte[] data = mmr.getEmbeddedPicture();
            if (data != null) {
                bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
            }
        } catch (IllegalArgumentException e) {
            // 处理无效媒体条目
            e.printStackTrace();
            bitmap = null;
        } finally {
            mmr.release();
        }

        songList.add(new Song(audioId, thisTitle, thisArtist, thisAlbum, bitmap));
    } while (cursor.moveToNext());

    cursor.close(); // 关闭Cursor释放资源
}

3. 优化:主动更新MediaStore(可选)

如果检测到文件不存在,可以通知系统更新MediaStore,避免后续查询再拿到无效条目:

// 删除MediaStore中无效的记录
contentResolver.delete(audioUri, null, null);

// 或者发送广播让系统重新扫描媒体文件
Intent scanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
scanIntent.setData(Uri.fromFile(audioFile));
sendBroadcast(scanIntent);

额外注意事项

  • 务必调用mmr.release()和cursor.close(),避免内存泄漏。
  • 在Android 13+,需要申请READ_MEDIA_AUDIO权限替代旧的READ_EXTERNAL_STORAGE。

内容的提问来源于stack exchange,提问作者b0ttas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 10:03:18