Android中释放与停止MediaPlayer时出现ANR问题求助
检查MediaPlayer回调的线程与锁竞争
虽然采用prepareAsync()异步准备,但MediaPlayer的状态回调(如onPrepared()、onError())默认在主线程执行。如果回调中存在同步锁、耗时逻辑,会和onStop()里的stop()/release()操作产生锁竞争,阻塞主线程。需确认所有回调仅处理UI状态变更,无阻塞性操作。排查准备与释放的竞态条件
当onStop()触发时,prepareAsync()的回调可能仍在主线程执行,此时调用stop()/release()会触发MediaPlayer内部同步锁等待。可通过原子变量标记状态,避免阻塞:private AtomicBoolean isPreparing = new AtomicBoolean(false); // 启动异步准备前标记 isPreparing.set(true); mediaPlayer.prepareAsync(); // onPrepared回调中更新状态 @Override public void onPrepared(MediaPlayer mp) { isPreparing.set(false); // 处理播放按钮显示逻辑 } // onStop中根据状态处理 @Override public void onStop() { super.onStop(); if (mediaPlayer != null) { if (isPreparing.get()) { mediaPlayer.reset(); // 避免等待准备完成 } else { mediaPlayer.stop(); } mediaPlayer.release(); mediaPlayer = null; } }模拟极端网络场景复现
本地测试未复现可能是网络环境稳定,prepareAsync()快速完成。可模拟弱网、网络中断场景,让MediaPlayer长时间处于准备状态,再触发Fragment的onStop(),验证是否出现ANR——此时MediaPlayer内部可能在等待网络回调,调用释放操作会阻塞主线程。分析Crashlytics的ANR调用栈
Crashlytics的ANR报告包含主线程快照,重点查看onStop()执行时主线程阻塞的具体方法(如MediaPlayer.stop()或release()内部),这能直接定位是MediaPlayer内部锁等待,还是外部代码阻塞。检查MediaPlayer实例的生命周期管理
若Fragment重建时未正确清理旧实例,会导致onStop()操作多个MediaPlayer实例,引发同步问题。需确保MediaPlayer为Fragment成员变量,在onStop()/onDestroyView()中彻底释放并置空,避免重复操作。
内容的提问来源于stack exchange,提问作者Nexussim Lements

