Android之MediaPlayer一个bug

本文主要记录使用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();
                }
            }
        }
    }
};

}

```

你可能感兴趣的:(Android,Error)