本文主要记录使用Android 的MediaPlayer时遇见的一个很奇怪的bug
播放音乐时会出现调用了start,但是没有声音出来
* 测试机器:华为Honor 8, Android 7.0;
* 需求:在音乐列表界面播放音乐,音乐分为本地音乐和网络音乐
* 工具:IjkMediaPlayer在播放网络音乐时差不多有个10秒的延时,就是用户点击到播放出来差不多要10秒(网没有问题,很快),播放本地音乐没有这个问题,暂时无解,所以使用Android 提供的MediaPlayer.
* 思路:按照我的理解嘛,把网络和本地的音乐播放代码用一个,所以使用异步prepare,(注意,这里埋下了问题),因为是在列表里,音乐有很多,点击音乐A播放,再次点击A是暂停,然后再次点击A是继续播放,很简单的功能,所以加了一个判断,记录了上一次的播放的音乐地址,如果不一样,就需要重新初始化Mediaplayer, 因为要联网获取,懒得开线程,直接使用MediaPlayer的异步操作prepareAsync(),写如下出来的代码
```
@Override
public void play(@NonNull String url) {
play(url, false);
}
@Override
public void play(@NonNull String url, boolean restart) {
synchronized (mPlayerLocker) {
try {
if (mMediaPlayer == null) {
mMediaPlayer = new MediaPlayer();
}
if (restart || !mLastPlayMusicUrl.equals(url)) {
mMediaPlayer.reset();
mMediaPlayer.setLooping(true);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setOnPreparedListener(mMediaPrepareListener);
mMediaPlayer.setVolume(0.5f, 0.5f);
mMediaPlayer.setDataSource(url);
mLastPlayMusicUrl = url;
mMusicIsPlaying = true;
mMediaPlayer.prepareAsync();
} else {
mMediaPlayer.start();
}
} catch (Exception e) {
e.printStackTrace();
D.e("play music error : " + e.getMessage() + " path:" + url + " file exists:" + new File(url).exists());
}
}
}
private MediaPlayer.OnPreparedListener
mMediaPrepareListener = new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
synchronized (mPlayerLocker) {
if (mMediaPlayer != null) {
if (mMusicIsPlaying) {
mMediaPlayer.start();
}
else {
mMediaPlayer.pause();
}
}
}
}
};
```
* 正常使用,上面的代码是没有问题,但是我们的操作可能比较不正常吧,注意上面的代码play(@NonNull String url, boolean restart),第二个参数如果是true,会重新初始化播放器,对同一首音乐,播放,暂停,播放,暂停,播放(重新初始化), 暂停,播放(重新初始化), 暂停,播放(重新初始化), 暂停,播放(重新初始化)…,差不多重复10次左右吧,会出现一次播放时没有声音,但是暂停后,再播放,就又正常了,代码确实去调用了,prepare()了,也start()了。
* 很郁闷,找不到问题,然后大胆猜测是不是异步播放导致的,代码暂时换成同步的,只测试本地的音乐,测试50次,没有复现,尝试了很多其他办法,发现同步是比较好的一种方式
* 解决方案:本地的用同步的方式,网络的用异步的方式,附上测试播放的代码
```
public class SlackMusicPlayer {
public final static SlackMusicPlayer instance = new SlackMusicPlayer();
private Thread mPrepareThread = null;
private SlackMusicPlayer() {
//
}
private MediaPlayer mMediaPlayer;
private String mLastPlayMusicUrl = "";
private boolean mMusicIsPlaying = false;
private final Object mPlayerLocker = new Object();
@Override
public void play(@NonNull String url) {
play(url, false);
}
@Override
public void play(@NonNull String url, boolean restart) {
synchronized (mPlayerLocker) {
try {
if (mMediaPlayer == null) {
mMediaPlayer = new MediaPlayer();
}
if (restart || !mLastPlayMusicUrl.equals(url)) {
mMediaPlayer.reset();
mMediaPlayer.setLooping(true);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setVolume(0.5f, 0.5f);
mMediaPlayer.setDataSource(url);
mLastPlayMusicUrl = url;
mMusicIsPlaying = true;
if (mPrepareThread != null) {
mPrepareThread.interrupt();
}
mPrepareThread = null;
if (url.startsWith("/")) {// 本地音乐文件
mMediaPlayer.setOnPreparedListener(null);
mPrepareThread = new Thread(new Runnable() {
@Override
public void run() {
try {
synchronized (mPlayerLocker) {
if (mMediaPlayer != null && mMusicIsPlaying) {
mMediaPlayer.prepare();
mMediaPlayer.start();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
mPrepareThread.start();
} else {
mMediaPlayer.setOnPreparedListener(mMediaPrepareListener);
mMediaPlayer.prepareAsync();
}
} else {
mMediaPlayer.start();
}
} catch (Exception e) {
e.printStackTrace();
D.e("play music error : " + e.getMessage() + " path:" + url + " file exists:" + new File(url).exists());
}
}
}
@Override
public void setVolume(float left, float right) {
synchronized (mPlayerLocker) {
try {
if (mMediaPlayer != null) {
mMediaPlayer.setVolume(left, right);
}
}
catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public void pause() {
synchronized (mPlayerLocker) {
try {
if (mMediaPlayer != null) {
mMediaPlayer.pause();
}
}
catch (Exception e) {
e.printStackTrace();
}
mMusicIsPlaying = false;
}
}
@Override
public void reset() {
synchronized (mPlayerLocker) {
try {
if (mMediaPlayer != null) {
mMediaPlayer.reset();
}
}
catch (Exception e) {
e.printStackTrace();
}
mMusicIsPlaying = false;
mLastPlayMusicUrl = "";
}
}
@Override
public void release() {
synchronized (mPlayerLocker) {
try {
if (mMediaPlayer != null) {
mMediaPlayer.release();
}
}
catch (Exception e) {
e.printStackTrace();
}
mMusicIsPlaying = false;
mMediaPlayer = null;
}
}
private MediaPlayer.OnPreparedListener
mMediaPrepareListener = new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
synchronized (mPlayerLocker) {
if (mMediaPlayer != null) {
if (mMusicIsPlaying) {
mMediaPlayer.start();
}
else {
mMediaPlayer.pause();
}
}
}
}
};
}
```