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
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值