package com.weishitechsub.quanminchangKmianfei.utils;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import androidx.annotation.NonNull;
import com.weishitechsub.quanminchangKmianfei.bean.MusicBean;
import java.util.List;
public class MusicPlayerManager {
private boolean isPreparing = false; // 是否正在准备
private boolean isPrepared = false; // 是否已准备好
private static volatile MusicPlayerManager instance; // 双检锁
private MediaPlayer mediaPlayer;
private OnPlaybackStateChangedListener listener;
private int currentPlayingPosition = -1; // 当前主列表播放位置
private String currentPlayingUrl = null;
// 私有构造
private MusicPlayerManager() {
// MediaPlayer 初始化延迟到首次使用
}
// 获取单例
public static MusicPlayerManager getInstance() {
if (instance == null) {
synchronized (MusicPlayerManager.class) {
if (instance == null) {
instance = new MusicPlayerManager();
}
}
}
return instance;
}
// 播放状态监听器
public interface OnPlaybackStateChangedListener {
void onPlaying(int position);
void onPaused();
void onCompletion();
void onError(String errorMsg);
}
public void setOnPlaybackStateChangedListener(OnPlaybackStateChangedListener listener) {
this.listener = listener;
}
/**
* 播放主列表中的歌曲
*/
public void play(@NonNull String musicUrl, int position) {
Log.d("MusicPlayer", /*"play() called - new url: " + musicUrl +*/ ", pos: " + position +
", isPlaying: " + (mediaPlayer != null && mediaPlayer.isPlaying()));
// 更新状态
this.currentPlayingPosition = position;
this.currentPlayingUrl = musicUrl;
// 强制释放旧资源
if (mediaPlayer != null) {
try {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.reset();
isPrepared = false;
isPreparing = false;
} catch (Exception e) {
Log.e("MusicPlayer", "Error resetting player", e);
release(); // 失败则完全释放
}
}
// 创建新的 MediaPlayer
if (mediaPlayer == null) {
mediaPlayer = new MediaPlayer();
setupListeners();
}
// 准备播放
prepareAndPlay(musicUrl, () -> {
if (listener != null) {
listener.onPlaying(position);
}
});
}
/**
* 内部方法:准备并播放音乐
*/
private void prepareAndPlay(String musicUrl, Runnable onPreparedAction) {
// 如果已经在准备同一资源,不重复处理
if (isPreparing && musicUrl.equals(currentPlayingUrl)) {
return;
}
// 标记为正在准备
isPreparing = true;
isPrepared = false;
try {
boolean needNewPlayer = (mediaPlayer == null);
if (needNewPlayer) {
mediaPlayer = new MediaPlayer();
setupListeners();
} else {
try {
mediaPlayer.reset(); // reset 会清除 prepared 状态
} catch (IllegalStateException e) {
Log.e("MusicPlayer", "reset failed", e);
mediaPlayer.release();
mediaPlayer = new MediaPlayer();
setupListeners();
}
}
// 设置音频属性
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mediaPlayer.setAudioAttributes(new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.setUsage(AudioAttributes.USAGE_MEDIA)
.build());
} else {
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
}
// 设置数据源并异步准备
final String url = musicUrl;
Handler mainHandler = new Handler(Looper.getMainLooper());
mainHandler.post(() -> {
try {
mediaPlayer.setDataSource(url);
mediaPlayer.setOnPreparedListener(mp -> {
isPreparing = false;
isPrepared = true;
mp.start();
onPreparedAction.run();
});
mediaPlayer.prepareAsync();
} catch (Exception e) {
isPreparing = false;
Log.e("MusicPlayer", "prepareAsync failed", e);
if (listener != null) {
listener.onError("无法准备播放: " + e.getMessage());
}
}
});
} catch (Exception e) {
isPreparing = false;
Log.e("MusicPlayer", "prepareAndPlay error", e);
if (listener != null) {
listener.onError("初始化失败: " + e.getMessage());
}
}
}
/**
* 设置 MediaPlayer 回调监听
*/
private void setupListeners() {
mediaPlayer.setOnCompletionListener(mp -> {
if (listener != null) {
listener.onCompletion();
}
});
mediaPlayer.setOnErrorListener((mp, what, extra) -> {
if (listener != null) {
listener.onError("播放错误: code=" + what + ", extra=" + extra);
}
return true; // 消费错误,不进入默认行为
});
}
/**
* 暂停播放
*/
public void pause() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
if (listener != null) {
listener.onPaused();
}
}
}
/**
* 继续播放
*/
public void resume() {
if (mediaPlayer != null && !mediaPlayer.isPlaying() && currentPlayingUrl != null) {
mediaPlayer.start();
if (listener != null) {
listener.onPlaying(currentPlayingPosition);
}
}
}
/**
* 是否正在播放
*/
public boolean isPlaying() {
return mediaPlayer != null && mediaPlayer.isPlaying();
}
/**
* 获取当前播放的位置(主列表索引)
*/
public int getCurrentPlayingPosition() {
return currentPlayingPosition;
}
/**
* 获取当前播放的音乐 URL
*/
public String getCurrentPlayingMusicUrl() {
return currentPlayingUrl;
}
/**
* 获取当前播放的歌曲信息(从主列表中查找)
*/
public MusicBean.DataBean getCurrentPlayingSong() {
List<MusicBean.DataBean> mainList = MusicCache.getMainMusicList();
if (mainList != null && currentPlayingPosition >= 0 && currentPlayingPosition < mainList.size()) {
MusicBean.DataBean song = mainList.get(currentPlayingPosition);
if (song != null && song.getMusic().equals(currentPlayingUrl)) {
return song;
}
}
// 回退:根据 URL 查找
if (mainList != null && currentPlayingUrl != null) {
for (int i = 0; i < mainList.size(); i++) {
MusicBean.DataBean song = mainList.get(i);
if (song != null && song.getMusic().equals(currentPlayingUrl)) {
currentPlayingPosition = i; // 自动修正索引
return song;
}
}
}
return null;
}
/**
* 获取当前播放列表(即主列表)
*/
public List<MusicBean.DataBean> getCurrentPlayingList() {
return MusicCache.getMainMusicList();
}
/**
* 跳转到指定时间
*/
public void seekTo(int milliseconds) {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
try {
mediaPlayer.seekTo(milliseconds);
} catch (IllegalStateException e) {
// 当前未初始化或未准备好
Log.e("MusicPlayer", "seekTo failed: not prepared", e);
}
}
}
/**
* 获取当前播放进度(毫秒)
*/
public int getCurrentPosition() {
if (mediaPlayer != null) {
try {
return mediaPlayer.getCurrentPosition();
} catch (IllegalStateException e) {
return 0;
}
}
return 0;
}
/**
* 获取音频总时长(毫秒)
*/
public int getDuration() {
if (mediaPlayer != null) {
try {
return mediaPlayer.getDuration();
} catch (IllegalStateException e) {
return 0;
}
}
return 0;
}
/**
* 释放 MediaPlayer 资源
*/
public void release() {
if (mediaPlayer != null) {
try {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
} catch (Exception e) {
// 忽略异常
} finally {
mediaPlayer.release();
mediaPlayer = null;
}
}
currentPlayingPosition = -1;
currentPlayingUrl = null;
}
}
2025-12-10 18:27:13.756 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 0, isPlaying: false
2025-12-10 18:27:13.770 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 1, isPlaying: false
2025-12-10 18:27:15.162 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 2, isPlaying: true
2025-12-10 18:27:15.274 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 3, isPlaying: false
2025-12-10 18:27:20.040 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 4, isPlaying: true
2025-12-10 18:27:22.840 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 5, isPlaying: true
2025-12-10 18:27:28.765 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 6, isPlaying: true
2025-12-10 18:27:28.888 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 7, isPlaying: false
2025-12-10 18:27:31.577 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 8, isPlaying: true
2025-12-10 18:27:34.480 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 9, isPlaying: true
2025-12-10 18:27:36.631 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 8, isPlaying: true
2025-12-10 18:27:39.231 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 7, isPlaying: true
2025-12-10 18:27:39.346 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 8, isPlaying: false
2025-12-10 18:27:46.654 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 7, isPlaying: true
2025-12-10 18:27:50.237 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 6, isPlaying: true
2025-12-10 18:27:52.783 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 5, isPlaying: true
2025-12-10 18:27:54.918 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 4, isPlaying: true
2025-12-10 18:27:54.975 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 5, isPlaying: false
2025-12-10 18:27:55.063 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 6, isPlaying: false
2025-12-10 18:27:58.164 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 5, isPlaying: true
2025-12-10 18:28:05.826 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 4, isPlaying: true
2025-12-10 18:28:12.167 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 3, isPlaying: true
2025-12-10 18:28:12.257 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 4, isPlaying: false
2025-12-10 18:28:20.466 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 3, isPlaying: true
2025-12-10 18:28:26.462 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 2, isPlaying: true
2025-12-10 18:28:34.679 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 1, isPlaying: true
2025-12-10 18:28:34.806 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 2, isPlaying: false
2025-12-10 18:28:34.923 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 3, isPlaying: false
2025-12-10 18:28:53.980 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 2, isPlaying: true
2025-12-10 18:28:54.055 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 3, isPlaying: false
2025-12-10 18:28:58.666 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 2, isPlaying: true
2025-12-10 18:29:06.386 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 1, isPlaying: true
2025-12-10 18:29:06.573 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 2, isPlaying: false
2025-12-10 18:29:06.653 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 3, isPlaying: false
2025-12-10 18:29:14.526 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 2, isPlaying: false
2025-12-10 18:29:14.586 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 3, isPlaying: false
2025-12-10 18:29:14.659 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 4, isPlaying: false
2025-12-10 18:29:20.794 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 3, isPlaying: false
2025-12-10 18:29:20.825 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 4, isPlaying: false
2025-12-10 18:29:22.548 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 3, isPlaying: true
2025-12-10 18:29:22.699 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 4, isPlaying: false
2025-12-10 18:29:23.530 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 3, isPlaying: true
2025-12-10 18:29:24.526 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 2, isPlaying: true
2025-12-10 18:29:24.878 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 1, isPlaying: true
2025-12-10 18:29:25.094 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 0, isPlaying: true
2025-12-10 18:29:25.292 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 37, isPlaying: true
2025-12-10 18:29:25.371 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 0, isPlaying: false
2025-12-10 18:29:25.522 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 37, isPlaying: true
2025-12-10 18:29:26.081 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 36, isPlaying: true
2025-12-10 18:29:26.243 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 37, isPlaying: false
2025-12-10 18:29:27.120 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 0, isPlaying: true
2025-12-10 18:29:27.248 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 1, isPlaying: false
2025-12-10 18:29:28.510 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 0, isPlaying: true
2025-12-10 18:29:31.320 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 1, isPlaying: true
2025-12-10 18:29:31.401 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 2, isPlaying: false
2025-12-10 18:29:32.097 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 3, isPlaying: true
2025-12-10 18:29:32.663 4747-4747 MusicPlayer com...itechsub.quanminchangKmianfei D , pos: 4, isPlaying: true打印结果去错
最新发布