Android之MediaPlayer一个bug

来源:互联网 发布:ubuntu安装golang1.7 编辑:程序博客网 时间:2024/06/15 10:34

本文主要记录使用Android 的MediaPlayer时遇见的一个很奇怪的bug

播放音乐时会出现调用了start,但是没有声音出来
* 测试机器:华为Honor 8, Android 7.0;
* 需求:在音乐列表界面播放音乐,音乐分为本地音乐和网络音乐
* 工具:IjkMediaPlayer在播放网络音乐时差不多有个10秒的延时,就是用户点击到播放出来差不多要10秒(网没有问题,很快),播放本地音乐没有这个问题,暂时无解,所以使用Android 提供的MediaPlayer.
* 思路:按照我的理解嘛,把网络和本地的音乐播放代码用一个,所以使用异步prepare,(注意,这里埋下了问题),因为是在列表里,音乐有很多,点击音乐A播放,再次点击A是暂停,然后再次点击A是继续播放,很简单的功能,所以加了一个判断,记录了上一次的播放的音乐地址,如果不一样,就需要重新初始化Mediaplayer, 因为要联网获取,懒得开线程,直接使用MediaPlayer的异步操作prepareAsync(),写如下出来的代码

```@Overridepublic void play(@NonNull String url) {    play(url, false);}@Overridepublic 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();@Overridepublic void play(@NonNull String url) {    play(url, false);}@Overridepublic 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());        }    }}@Overridepublic void setVolume(float left, float right) {    synchronized (mPlayerLocker) {        try {            if (mMediaPlayer != null) {                mMediaPlayer.setVolume(left, right);            }        }        catch (Exception e) {            e.printStackTrace();        }    }}@Overridepublic void pause() {    synchronized (mPlayerLocker) {        try {            if (mMediaPlayer != null) {                mMediaPlayer.pause();            }        }        catch (Exception e) {            e.printStackTrace();        }        mMusicIsPlaying = false;    }}@Overridepublic void reset() {    synchronized (mPlayerLocker) {        try {            if (mMediaPlayer != null) {                mMediaPlayer.reset();            }        }        catch (Exception e) {            e.printStackTrace();        }        mMusicIsPlaying = false;        mLastPlayMusicUrl = "";    }}@Overridepublic 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();                }            }        }    }};

}

```