Android应用中USB存储连接时MediaPlayer的onCompletion()被意外调用的问题修复求助
嘿,看起来你遇到了一个挺恼人的问题——USB存储一连接到设备,正在播放的视频明明还没结束,MediaPlayer的onCompletion()却被直接触发了对吧?我来帮你分析下可能的原因,再给出针对性的解决办法。
可能的原因
这种情况通常是因为USB连接时,系统会触发存储挂载/扫描操作,导致MediaPlayer正在读取的视频文件路径暂时不可用;或者你的USB文件更新逻辑间接干扰了MediaPlayer的播放状态,让它误以为播放已经完成。
具体解决方案
1. 在onCompletion()中添加播放状态校验
先判断MediaPlayer是否真的播放完毕,过滤掉意外触发的回调:
override fun onCompletion(mp: MediaPlayer?) { // 留1秒左右的误差,避免因为播放进度的微小偏差误判 val isActuallyCompleted = mp?.let { !it.isPlaying && it.currentPosition >= it.duration - 1000 } ?: false if (isActuallyCompleted) { // 这里放你原来的播放完成处理逻辑 } else { // 属于意外触发,尝试恢复播放或者忽略 mp?.start() } }
2. 检查onDownloadFinished()的逻辑是否干扰MediaPlayer
你的PlayerViewModel实现了USBDownloadListener,在onDownloadFinished()里的代码会不会间接停止或释放了MediaPlayer?比如有没有调用mediaPlayer.stop()、mediaPlayer.release()这类方法?如果有的话,需要调整这部分逻辑,确保USB文件更新时不会影响正在播放的视频。
3. 监听USB挂载/卸载事件,提前保护MediaPlayer
在USBIOManager的广播接收器里区分USB动作,提前暂停/恢复MediaPlayer,避免它因为数据源中断触发异常:
override fun onReceive(context: Context, intent: Intent) { when(intent.action) { Intent.ACTION_MEDIA_UNMOUNTED -> { // USB即将卸载,先暂停播放 (downloadListener as? PlayerViewModel)?.pausePlayback() } Intent.ACTION_MEDIA_MOUNTED -> { // USB挂载完成,更新文件后恢复播放 updateUSBFiles(context) (downloadListener as? PlayerViewModel)?.resumePlayback() } // 处理其他USB相关动作 } }
然后在PlayerViewModel中添加对应的暂停/恢复方法:
private var mediaPlayer: MediaPlayer? = null // 假设你持有MediaPlayer实例 fun pausePlayback() { mediaPlayer?.takeIf { it.isPlaying }?.pause() } fun resumePlayback() { mediaPlayer?.takeIf { !it.isPlaying }?.start() }
4. 利用OnErrorListener捕获存储异常
你的ViewModel已经实现了MediaPlayer.OnErrorListener,可以在这里处理因USB连接导致的IO错误,避免触发onCompletion():
override fun onError(mp: MediaPlayer?, what: Int, extra: Int): Boolean { // 捕获IO类错误(通常是文件路径不可用) if (what == MediaPlayer.MEDIA_ERROR_IO) { try { // 尝试重置MediaPlayer并重新加载视频 mp?.reset() mp?.setDataSource(yourVideoFilePath) // 替换成你的视频路径 mp?.prepare() mp?.start() } catch (e: Exception) { e.printStackTrace() } return true // 返回true表示已处理错误,不会触发onCompletion } return false }
你可以先从检查onDownloadFinished()的逻辑开始,再逐步尝试上面的方案,应该能解决这个问题。
备注:内容来源于stack exchange,提问作者jpskgc

