MediaPlayer中onCompletion和onError的坑

问题:

在做音乐播放功能时,发现点击下一曲或者上一曲有时会跳过曲目播放,通过检查下一曲next()和上一曲pre()方法逻辑并没有发现什么问题,为什么会出现这种情况呢?

基本功能:

1.可以手动点击上一曲下一曲
2.设置OnCompletionListener当播放完成时自动播放下一曲
3.播放时通过Handler循环获取当前播放进度和总时长更新视图

解决过程:

分析:通过打印日志发现,onCompletion方法在歌曲未播放完成时被调用了!很奇怪的问题,常识上来讲,只有音乐播放完成时此方法才会被调用。百思不得其解的情况下,忽然想到代码中只设置了OnPreparedListener和OnCompletionListener会不会是播放过程中发生了什么错误?于是设置OnErrorListener打印日志同时当错误回调时也执行下一曲:
这里写图片描述

这里写图片描述
可以看到position:6位置的确发生了错误直接跳到了7位置准备播放。但是,刚刚提到的问题是onCompletion被调用了,怎么添加了OnErrorListener后onCompletion不再回调,只回调了onError?

不理解,好吧,翻一下源码。于是,MediaPlayer的Handler处理消息有这么一段代码
这里写图片描述

也就是说当有设置MediaPlayer的OnErrorListener时就调用onError()方法,如果error没有被处理,也即没有设置错误监听或者onError()方法返回false(通过log验证结论),就调用OnCompletionListener的onCompletion()方法。

好吧,道理我都懂,但是哪里产生的错误呢?回到onError()中打印日志时顺带把错误代码打印了一下发现错误代码-38,搜索了一下网上的答案大概有如下结论:

1) 当一个MediaPlayer对象被新建或调用reset()方法之后,它处于空闲状态,在调用release方法之后,才会处于结束状态。
2) 一个新建的MediaPlayer对象在调用getCurrenProgress()、getDuration、
getVideoHeight()、getVideoWith()、setAudioStreamType(int)、
setLooping(boolean)、setVolume(float,float)、pause()、start()、stop()、
seekTo()、prepare()、prepareAsync()方法时,不会触发OnErrorListenerError()事件,但是
MediaPlayer对象如果调用了reset()方法后,再使用这些方法则会触发OnErrorListenerError()事件。

以上结论不一定都准确,但给了一个参考方向。
过滤了一遍代码,又根据log中error出现位置的不确定性,终于确定是因为handler中循环调用getDuration(),当点击下一曲后MediaPlayer已释放资源,下一曲资源还没有准备完成时,刚好handleMessage中调用了getDuration()就会发生错误。于是在点击时先移除了相应的消息,完美解决了问题!

总之,在onCompletion()中完成相应的业务逻辑时一定要谨慎,最好要添加OnErrorListener监听错误信息并返回true。

发布了13 篇原创文章 · 获赞 13 · 访问量 1万+
展开阅读全文

setOnCompletion方法为什么有时候会执行两次,有时候一次都不执行?

12-08

class OnCompletionListener implements android.media.MediaPlayer.OnCompletionListener { @Override public void onCompletion(MediaPlayer mp) { Log.i("mp3", "服务执行了OnCompletionListener方法"); statethreadFlag = true; mp.stop(); if (currIndex >= (list.size() - 1)) { Toast.makeText(getApplicationContext(), "歌曲全部播放完毕", Toast.LENGTH_LONG).show(); } else { currIndex++; start(); } } } @Override public int onStartCommand(Intent intent, int flags, int startId) { // TODO Auto-generated method stub Log.i("mp3", "服务执行了onstartcommand方法"); player = new MediaPlayer(); bundle = intent.getBundleExtra("sendListToService"); list = (ArrayList<HashMap<String, String>>) bundle.getSerializable("arraylist"); currIndex = bundle.getInt("currIndex"); start(); player.setOnCompletionListener(new OnCompletionListener()); return super.onStartCommand(intent, flags, startId); } public void start() { Log.i("mp3", "服务执行了start方法,开始播放歌曲"); if (bundle.getBoolean("flag")) { hMap = list.get(currIndex); player.reset(); try { player.setDataSource(hMap.get("path")); player.prepare(); // Log.i("mp3", "播放器准备完毕"); } catch (Exception e) { e.printStackTrace(); } player.start(); serviceFlag = 1; statethreadFlag = false; new Thread(new StateThread()) { }.start(); } else { } } 播放器是写在服务中的,想让播放器在放完一首歌后自动播放下一曲,可是有时候会重复一首或者跳一首和两首歌。找了半天也不知道哪里出了问题。 问答

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览