Android音乐播放器亮屏切歌正常息屏卡顿故障排查解决求助
解决方案
根因说明
亮屏时CPU处于活跃状态,SD卡IO、MediaPlayer初始化都能正常执行;息屏后系统为了省电会自动将CPU切换到低功耗休眠状态,普通服务优先级的进程IO操作会被限流甚至暂停,导致MediaPlayer加载音轨卡顿。
连接蓝牙耳机时系统会自动持有音频相关的唤醒锁保持CPU活跃,所以不会出现卡顿。
具体修改步骤
1. 新增唤醒锁权限
在AndroidManifest.xml中添加唤醒锁权限:
<uses-permission android:name="android.permission.WAKE_LOCK" />
2. MusicService中添加唤醒锁持有逻辑
在MusicService类中添加唤醒锁相关变量和方法:
private PowerManager.WakeLock wakeLock; @Override public void onCreate() { super.onCreate(); // 初始化唤醒锁 PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MusicApp:WakeLockTag"); wakeLock.setReferenceCounted(false); // 原有初始化逻辑不变 ... } // 播放时持有唤醒锁 private void acquireWakeLock() { if (!wakeLock.isHeld()) { wakeLock.acquire(); } } // 暂停/停止时释放唤醒锁 private void releaseWakeLock() { if (wakeLock.isHeld()) { wakeLock.release(); } } @Override public void onDestroy() { super.onDestroy(); releaseWakeLock(); // 原有销毁逻辑不变 ... }
在playMedia、start方法中调用acquireWakeLock(),在pause、stop、releaseMP方法中调用releaseWakeLock()。
3. 替换同步prepare为异步prepareAsync
你当前的同步prepare()会阻塞主线程,息屏CPU降频时卡顿概率极高,修改为异步加载:
public void createMediaPlayer(int positionInner) { position = positionInner; uri = Uri.parse(musicFiles.get(position).getPath()); if (mediaPlayer == null) { mediaPlayer = new MediaPlayer(); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.setOnPreparedListener(this); mediaPlayer.setOnCompletionListener(this); } else { mediaPlayer.reset(); } try { mediaPlayer.setDataSource(getApplicationContext(), uri); } catch (IOException ioException) { ioException.printStackTrace(); } // 替换prepare()为prepareAsync() mediaPlayer.prepareAsync(); } @Override public void onPrepared(MediaPlayer mp) { acquireWakeLock(); mp.start(); // 刷新通知栏 showNotification(R.drawable.ic_pause); }
删除原有prepare()方法,删除playMedia方法中的mediaPlayer.start()调用,加载完成后会自动在onPrepared回调中执行播放。
4. 修复前台服务逻辑
只要处于播放状态就保持前台服务优先级,不要随意调用stopForeground:
void showNotification(int playPauseBtn){ ... if (isPlaying()) { startForeground(2, notification); } else { stopForeground(false); } }
5. 优化切歌逻辑,复用MediaPlayer实例
删除nextBtnClicked中重复的release()调用,复用现有MediaPlayer实例减少初始化耗时:
public void nextBtnClicked() { // 删除原有musicService.stop()和musicService.release()调用 if(SHUFFLE && !REPEAT){ POSITION_PLAY = getRandom(ListSongs.size() - 1); } else if(!SHUFFLE && !REPEAT){ POSITION_PLAY = ((POSITION_PLAY + 1) % ListSongs.size()); } // 直接调用createMediaPlayer即可,内部会reset复用实例 musicService.createMediaPlayer(POSITION_PLAY); if(is_live_player_activity) { metaData(uri); } playPauseBtn.setBackgroundResource(R.drawable.ic_pause); }
内容的提问来源于stack exchange,提问作者Alex Goodman
相关产品推荐
相关产品推荐

