调用MediaPlayer获取播放位置抛出IllegalStateException的原因是什么?
MediaPlayer 随机抛出IllegalStateException异常原因及解决方案
Android MediaPlayer 是严格基于状态机设计的系统组件,只有处于 Prepared、Started、Paused、PlaybackCompleted 这几种状态时,调用 getCurrentPosition() 和 getDuration() 才是合法操作,其他状态下调用上述方法就会触发 IllegalStateException,你的代码出现随机异常的具体原因如下:
- 定时任务未随MediaPlayer生命周期同步终止:你在
onPrepared回调中启动了每秒执行的Timer定时任务,但当MediaPlayer执行stop()、reset()、release()操作(比如用户切歌、退出播放、播放完成销毁实例)后,Timer任务依然会按周期执行,此时访问mp.currentPosition、mp.duration时MediaPlayer已经处于非法状态,就会抛出异常。 - 跨线程状态竞争:Timer任务运行在独立的后台线程,和主线程的MediaPlayer状态修改操作没有做同步处理,可能出现刚好在Timer执行逻辑的瞬间,主线程将MediaPlayer切换到了非法状态,导致异常随机触发。
- 异常场景未兜底:当MediaPlayer触发
onError()回调后,会直接进入Error状态,此时如果Timer任务还在运行,调用状态相关方法也会直接抛出异常。
修复方案
- 首先在MediaPlayer生命周期结束的所有节点(比如
onCompletion回调、onError回调、服务销毁、用户主动停止播放的逻辑中),主动调用Timer的cancel()方法终止定时任务,同时将Timer实例置空避免重复启动。 - 访问MediaPlayer状态参数前先做合法性校验,也可以增加异常捕获兜底,避免崩溃:
override fun onPrepared(mp: MediaPlayer?) { mp ?: return mp.start() timer.schedule(object : TimerTask() { override fun run() { try { val currentProgress = mp.currentPosition val maxProgress = mp.duration val intent = Intent(SONG_INTENT) intent.putExtra(SONG_KEY, PROGRESS_BROADCAST) intent.putExtra(CURRENT_PROGRESS, currentProgress) intent.putExtra(MAX_PROGRESS, maxProgress) LocalBroadcastManager.getInstance(this@AudioPlayerService).sendBroadcast(intent) } catch (e: IllegalStateException) { // 出现非法状态直接终止定时任务 cancel() } } }, 0, 1000) }
内容的提问来源于stack exchange,提问作者Muhammad Sajid
相关产品推荐
相关产品推荐

