使用just_audio与audio_service实现播客从用户上次播放位置续播时遭遇IllegalSeekPositionException异常的问题
解决Just Audio + ExoPlayer续播时的IllegalSeekPositionException问题
你遇到的核心问题是媒体资源尚未完成加载就执行了seek操作,导致ExoPlayer判定跳转位置非法,进而抛出IllegalSeekPositionException。结合你使用的Just Audio库,我整理了几个针对性的解决步骤:
1. 调整播放流程:先等媒体加载完成,再执行seek+play
你之前先调用audioHandler.play()再seek的逻辑存在漏洞——播放启动后,媒体资源可能仍在缓冲,ExoPlayer还未获取到音频的总时长,此时传入的lastPlayed位置会被判定为超出范围(因为此时duration还是null或0)。
正确的执行顺序应该是:
- 先加载音频资源
- 监听音频的
duration状态,确认资源加载完成(duration不为null) - 先执行
seek(lastPlayed),再启动播放
示例代码(Flutter)
// 初始化并加载目标播客资源 await audioHandler.setAudioSource(AudioSource.uri(Uri.parse(yourPodcastUrl))); // 等待音频duration加载完成(确保资源已就绪) await audioHandler.duration.firstWhere((d) => d != null); // 读取保存的播放位置并校验有效性 final lastPlayed = await getSavedPlayPosition(); // 你自定义的读取保存位置方法 final duration = audioHandler.duration.value ?? 0; if (lastPlayed != null && lastPlayed > 0 && lastPlayed <= duration) { await audioHandler.seek(lastPlayed); } // 最后启动播放 await audioHandler.play();
2. 严格校验保存的播放位置有效性
抛出IllegalSeekPositionException的另一个常见原因是你保存的lastPlayed值本身非法:比如值为负数,或者大于音频的实际总时长。每次读取保存位置后,务必添加校验逻辑:
- 确保
lastPlayed >= 0 - 确保
lastPlayed <= 音频总时长
若不满足条件,默认从0位置开始播放。
3. 捕获异常并做降级处理
为避免崩溃影响用户体验,建议给seek操作添加异常捕获,当出现非法位置异常时,自动回退到开头播放:
try { await audioHandler.seek(lastPlayed); } catch (e) { if (e is PlatformException && e.code.contains('IllegalSeekPosition')) { await audioHandler.seek(0); } // 可添加其他异常的处理逻辑 } await audioHandler.play();
额外提示:利用Just Audio的自动续播特性
Just Audio本身支持播放状态的自动保存,你可以在初始化播放器时配置相关参数,让系统帮你管理播放位置,减少手动处理的成本:
final player = AudioPlayer( androidAudioAttributes: AndroidAudioAttributes( contentType: AndroidAudioAttributes.CONTENT_TYPE_MUSIC, usage: AndroidAudioAttributes.USAGE_MEDIA, ), ); // 播放器会自动保存播放状态,重启后可直接恢复 await player.load(); await player.play();
内容的提问来源于stack exchange,提问作者Demondre Livingston
相关产品推荐
相关产品推荐

