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

Android平台MediaPlayer无法启动问题排查求助

解决Android媒体播放器Scoped Storage权限拒绝问题

这个EACCES (Permission denied)错误是因为**Android 10及以上版本引入的Scoped Storage(分区存储)**限制导致的——哪怕你申请了READ_EXTERNAL_STORAGE权限,直接通过文件路径访问外部存储的文件也会被系统拒绝。下面是具体的原因分析和解决方案:

问题根源

从Android 10(API 29)开始,系统默认启用分区存储,禁止应用直接通过绝对文件路径(比如/storage/emulated/0/Download/Naruto - Main Theme.mp3)访问外部存储文件。你当前通过MediaStore.Audio.Media.DATA获取的路径,在高版本系统上已经失去了直接访问的权限。

解决方案

我们需要改用Content URI(媒体库提供的统一资源标识)来访问音频文件,同时调整代码逻辑适配分区存储规范:

1. 修改MainActivity的歌曲加载逻辑

不再依赖DATA列获取文件路径,而是获取歌曲的Content URI,并更新Song类的字段存储URI字符串:

private void loadSongs() {
    Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
    String select = MediaStore.Audio.Media.IS_MUSIC + "!=0";
    // 只查询必要字段,避免冗余
    String[] projection = {
        MediaStore.Audio.Media._ID,
        MediaStore.Audio.Media.ARTIST,
        MediaStore.Audio.Media.DISPLAY_NAME
    };
    Cursor cursor = getContentResolver().query(uri, projection, select, null, null);
    if(cursor!=null){
        while (cursor.moveToNext()){
            long songId = cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media._ID));
            String author = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST));
            String title = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME));
            // 构建歌曲的Content URI
            Uri songUri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, songId);
            songs.add(new Song(title, author, songUri.toString()));
        }
        cursor.close(); // 记得关闭Cursor,避免内存泄漏
    }
    recyclerView.setAdapter(new MusicAdapter(songs,this));
}

2. 调整MusicAdapter的播放逻辑

通过Content URI直接给MediaPlayer设置数据源,替代原来的文件路径方式:

private void startMusic(Integer pos) {
    // 先停止之前的播放,避免资源占用
    if(mediaPlayer != null){
        stopPlayer();
    }
    mediaPlayer = new MediaPlayer();
    try {
        Uri songUri = Uri.parse(songs.get(pos).song_Url);
        // 使用Content URI设置MediaPlayer数据源
        mediaPlayer.setDataSource(context, songUri);
        mediaPlayer.prepare();
        mediaPlayer.start();
    } catch (IOException e) {
        e.printStackTrace();
        Log.e("MusicAdapter", "播放失败: " + e.getMessage());
    }
}

3. 额外优化建议

  • 权限提示优化:在权限被拒绝时给用户明确提示,提升体验:
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if(requestCode == 111){
        if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
            loadSongs();
        } else {
            Toast.makeText(this, "需要存储权限才能读取本地歌曲", Toast.LENGTH_SHORT).show();
        }
    }
}
  • 资源释放:在Activity销毁时调用MusicAdapter的stopPlayer方法,释放MediaPlayer资源,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 05:53:14