Android 8.1(API27)音乐播放器报MediaPlayer error: attachnewplayer called in state 64
解决Android MediaPlayer错误:attachnewplayer called in state 64
这个错误我之前帮不少开发者排查过,本质是MediaPlayer状态机违规操作导致的——State 64对应的是MediaPlayer的PREPARED状态(常量值为MediaPlayer.PREPARED),在这个状态下直接执行setDataSource或尝试重新关联播放器,就会触发这个错误,因为MediaPlayer的状态流转是严格受控的,不允许跳过重置步骤直接切换数据源。
结合你使用的Android 8.1(API 27)和提供的代码,给你几个针对性的解决方案:
1. 切换歌曲前正确重置MediaPlayer状态
在调用setDataSource之前,必须先将MediaPlayer重置到Idle状态,再重新初始化数据源并准备播放。修改你的playSong()方法如下:
public void playSong() { // 先处理MediaPlayer的状态重置 if (player != null) { // 如果播放器已存在,先重置到Idle状态 player.reset(); } else { // 如果播放器未初始化,创建新实例并设置必要监听 player = new MediaPlayer(); // 设置准备完成监听,准备好后自动播放 player.setOnPreparedListener(mediaPlayer -> mediaPlayer.start()); // 设置错误监听,捕获播放过程中的异常 player.setOnErrorListener((mediaPlayer, what, extra) -> { Log.e("MediaPlayerError", "Error code: " + what + ", extra: " + extra); return false; // 返回false让系统处理默认错误逻辑 }); } Song playSong = songs.get(songPosn); songTitle = playSong.getTitle(); long currSong = playSong.getID(); Uri trackUri = ContentUris.withAppendedId( android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, currSong ); try { player.setDataSource(getApplicationContext(), trackUri); // 推荐用prepareAsync()避免阻塞主线程(尤其是UI线程) player.prepareAsync(); } catch (IOException e) { e.printStackTrace(); Toast.makeText(getApplicationContext(), "无法加载音频文件", Toast.LENGTH_SHORT).show(); } }
2. 同步MediaController的上下首按钮逻辑
确保MediaController的skipToPrevious()和skipToNext()方法调用的是上述修改后的playSong(),而不是直接操作MediaPlayer而不重置状态。比如你的MediaPlayerControl实现类中:
@Override public void skipToNext() { songPosn = (songPosn + 1) % songs.size(); playSong(); } @Override public void skipToPrevious() { songPosn = (songPosn - 1 + songs.size()) % songs.size(); playSong(); }
3. 适配Android 8.1的额外注意事项
- 后台播放权限:Android 8.0及以上对后台播放有严格限制,建议将音乐播放逻辑放在**前台服务(Foreground Service)**中,避免被系统回收,同时保证MediaController能正常交互。
- 存储权限:确保你已经申请了
READ_EXTERNAL_STORAGE权限(API 27可直接在Manifest中声明),否则无法获取媒体文件的URI。
错误原因再梳理
当你从列表选歌或点击MediaController的上下首时,之前的MediaPlayer可能已经处于PREPARED甚至STARTED状态,此时直接调用setDataSource会违反MediaPlayer的状态机规则——MediaPlayer必须从Idle状态开始,依次经过Initialized→Prepared才能进入播放状态,切换歌曲时必须先通过reset()回到Idle,再重新初始化。
内容的提问来源于stack exchange,提问作者Arpit Sharma
相关产品推荐
相关产品推荐

