You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android Studio开发音乐播放器时MediaPlayer创建失败及setDataSource报错问题求助

解决Android MediaPlayer "Unable to create media player" 错误

嘿,我看你在开发音乐播放器时遇到了MediaPlayer的初始化问题,咱们一步步来搞定它!

首先拆解下你遇到的错误核心根源:

  • 线程逻辑搞反了:你把setDataSource()prepare()这些耗时的IO操作放到了UI线程(runOnUiThread里),这不仅可能触发ANR,还会干扰MediaPlayer的正常初始化流程,这是导致报错的主要原因之一。
  • MediaPlayer状态流转混乱:切换歌曲时的状态处理顺序有问题,监听器绑定、数据源设置的时机不对,也会导致初始化失败。
  • 潜在的文件权限/有效性问题songList.get(pos).getSongFile()返回的Uri可能无效,或者你的App没有读取该文件的权限(比如外部存储文件需要申请READ_EXTERNAL_STORAGE权限,Android 10+还要注意Scoped Storage规则)。

修复后的代码示例

我帮你调整了线程逻辑和状态管理,你可以参考:

@Override 
public void onChanged(int pos) { 
    // 先处理当前MediaPlayer的状态,避免内存泄漏
    if(songPlayer != null && songPlayer.isPlaying()){ 
        songPlayer.stop(); 
        songPlayer.release(); 
    } 
    // 创建新的MediaPlayer实例(复用前需确保状态完全重置)
    songPlayer = new MediaPlayer();
    songPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); 

    // 先绑定PreparedListener,避免错过回调时机
    songPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { 
        @Override 
        public void onPrepared(MediaPlayer mediaPlayer) { 
            // 这里是UI操作,安全在主线程执行
            int totalDuration = mediaPlayer.getDuration(); 
            // 优化时长格式化逻辑,避免冗余转换
            long minutes = TimeUnit.MILLISECONDS.toMinutes(totalDuration);
            long seconds = TimeUnit.MILLISECONDS.toSeconds(totalDuration) - 
                           TimeUnit.MINUTES.toSeconds(minutes);
            String duration = String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds); 
            endTime.setText(duration); 
            isPlaying = true; 
            mediaPlayer.start(); 
            songBar.setMax(totalDuration); 
            playPauseImg.setImageResource(R.drawable.ic_pause); 
        } 
    }); 

    // 子线程处理耗时的IO操作,不阻塞UI
    new Thread(new Runnable() { 
        @Override 
        public void run() { 
            try { 
                Uri songUri = songList.get(pos).getSongFile();
                // 先检查Uri有效性
                if(songUri == null){
                    throw new IOException("无效的歌曲路径");
                }
                songPlayer.setDataSource(getApplicationContext(), songUri); 
                songPlayer.prepare(); // 同步prepare在子线程执行完全没问题
            } catch (IOException e){ 
                e.printStackTrace(); 
                // 回到UI线程显示错误提示
                runOnUiThread(() -> 
                    Toast.makeText(MainActivity.this, "无法播放该曲目:" + e.getMessage(), Toast.LENGTH_SHORT).show()
                ); 
                // 初始化失败时及时释放MediaPlayer
                if(songPlayer != null){
                    songPlayer.release();
                    songPlayer = null;
                }
            } 
        } 
    }).start(); 
}

额外注意事项

  • 权限检查:如果歌曲文件在外部存储,记得在Manifest中添加权限,并且在运行时申请(Android 6+):
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    
    Android 10及以上推荐使用MediaStore获取歌曲,尽量适配Scoped Storage规则,避免申请过于宽泛的存储权限。
  • 内存管理:在Activity销毁时务必调用songPlayer.release(),彻底释放资源,避免内存泄漏。
  • 异常细化:可以在catch块中区分不同的IOException类型(比如文件不存在、权限不足),给用户更精准的错误提示。

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

火山引擎 最新活动