音樂播放器進度條在未播放狀態下拖動會報錯(如 NullPointerException 或 IllegalStateException),因 MediaPlayer 未初始化或未處於準備狀態,調用 seekTo() 導致異常。
// 1. 定義播放狀態枚舉
enum PlayState { IDLE, PREPARING, PLAYING, PAUSED, COMPLETED, ERROR }
private PlayState currentState = PlayState.IDLE;
// 2. SeekBar 觸摸監聽中判斷狀態
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
if (currentState == PlayState.IDLE || currentState == PlayState.ERROR) {
// 未播放或錯誤狀態,取消本次拖動
Toast.makeText(ctx, "請先播放音樂", Toast.LENGTH_SHORT).show();
// 關鍵:移除回調或標記忽略後續進度變更
isUserSeeking = false;
return;
}
isUserSeeking = true; // 標記用戶正在拖動,暫停自動更新進度
if (mediaPlayer != null) mediaPlayer.pause(); // 拖動時暫停播放
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (!fromUser || !isUserSeeking) return; // 非用戶操作或非拖動狀態忽略
// 可選:實時顯示當前拖動時間
tvCurrentTime.setText(formatTime(progress));
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
if (!isUserSeeking) return;
isUserSeeking = false;
if (mediaPlayer != null && currentState != PlayState.IDLE) {
mediaPlayer.seekTo(seekBar.getProgress()); // 安全調用
mediaPlayer.start(); // 恢復播放
}
}
});
// 3. 播放狀態變更時同步 SeekBar 狀態
private void updatePlayState(PlayState newState) {
currentState = newState;
boolean enabled = (newState == PlayState.PLAYING || newState == PlayState.PAUSED);
seekBar.setEnabled(enabled); // 核心:未播放時禁用 SeekBar
seekBar.setClickable(enabled);
if (!enabled) seekBar.setProgress(0); // 重置進度
}
MediaPlayer 操作前檢查 mediaPlayer != null 且狀態合法。isUserSeeking 區分用戶拖動與代碼自動更新進度,避免衝突。此模式適用於所有媒體播放控件(VideoView、ExoPlayer、MediaController),是穩健播放器開發的基礎範式。