Android之MediaPlayer一个bug
本文主要记录使用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(); } } } }};
}
```
更多相关文章
- 没有一行代码,「2020 新冠肺炎记忆」这个项目却登上了 GitHub 中
- 为什么移动端跨平台开发不靠谱?
- Android(安卓)使用LeakCanary 检测内存泄露
- Android(安卓)4.0 系统源代码将于本月17日放出
- Android(安卓)HAL层与Linux Kernel层驱动开发简介
- Android(安卓)APK及导出JAR包的代码混淆
- Android(安卓)四大组件 —— 广播(广播机制解析)
- # Android+Java后端(Springboot,Mybatis)开源小商店项目
- Android(安卓)UI绘制流程(一)