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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 12:45:04