Flutter中AudioPlayers包Android端播放异常原因排查
问题分析:Widget音频播放行为不稳定及错误日志解读
需求为Widget渲染完成后循环播放音频,销毁时停止,但当前代码运行行为不稳定:有时正常循环播放,有时仅播放一次,有时完全不播放。真实Android设备测试时出现如下错误日志:
E/MediaPlayerNative(21219): stop called in state 1, mPlayer(0x0) E/MediaPlayerNative(21219): error (-38, 0) V/MediaPlayer(21219): resetDrmState: mDrmInfo=null mDrmProvisioningThread=null mPrepareDrmInProgress=false mActiveDrmScheme=false V/MediaPlayer(21219): cleanDrmObj: mDrmObj=null mDrmSessionId=null V/MediaPlayer(21219): resetDrmState: mDrmInfo=null mDrmProvisioningThread=null mPrepareDrmInProgress=false mActiveDrmScheme=false V/MediaPlayer(21219): cleanDrmObj: mDrmObj=null mDrmSessionId=null
对应的Widget代码:
class TopButtonBackground extends StatefulWidget { const TopButtonBackground({ Key? key, }) : super(key: key); @override State<TopButtonBackground> createState() => _TopButtonBackgroundState(); } class _TopButtonBackgroundState extends State<TopButtonBackground> with SingleTickerProviderStateMixin { Animation<double>? _animation; AnimationController? _controller; AudioPlayer player = AudioPlayer(); static AudioCache audioCache = AudioCache(prefix: 'assets/'); @override void initState() { super.initState(); _playAudio(); _controller = AnimationController(duration: const Duration(seconds: 12), vsync: this); _animation = Tween<double>(begin: 0, end: 1).animate(_controller!) ..addListener(() { setState(() {}); }); _controller?.forward(); } void _playAudio() async { final url = await audioCache.load("direct_request_tune.mp3"); player.setReleaseMode(ReleaseMode.loop); player.play(DeviceFileSource(url.path)); } @override void dispose() { _controller?.dispose(); player.dispose(); super.dispose(); } @override Widget build(BuildContext context) { if (_animation != null) { return Opacity( opacity: min((sin(_animation!.value * 50) + 1.3) / 2, 1), child: Container( height: 70, width: MediaQuery.of(context).size.width * _animation!.value, color: Colors.grey.withOpacity(.2)), ); } return Container(height: 70); } }
行为不稳定及错误原因分析
1. 音频播放时机与Widget生命周期不匹配
initState中直接调用_playAudio(),但此时Widget还未完成渲染(build方法尚未执行完毕),音频播放操作可能因Widget未完全挂载而被系统中断或优先级降低,导致播放行为不可预测。
2. AudioPlayer状态管理不当
player.dispose()在dispose方法中直接调用,但未先停止播放或重置播放器状态。错误日志中的stop called in state 1表明调用停止操作时,播放器处于不允许该操作的状态(如未初始化完成或已释放),触发error (-38, 0)(代表操作无效,状态不匹配)。_playAudio中设置循环模式后直接调用play,未处理播放过程中的异常或状态回调,一旦播放出现错误(如文件加载延迟、播放器状态异常),无法自动恢复,导致播放中断或无法启动。
3. 异步加载与播放的时序问题
audioCache.load是异步操作,若文件加载完成前Widget因setState触发重建或生命周期变化,可能导致播放器实例状态混乱。比如Widget快速重建时,可能出现多个播放器实例竞争资源,或旧实例被提前释放。
4. 缺少状态监听与错误处理
代码未对AudioPlayer的播放状态(如onPlayerComplete、onPlayerError)进行监听,无法及时捕获播放过程中的错误并处理,出现问题时无法恢复播放,表现为仅播放一次或完全不播放。
内容的提问来源于stack exchange,提问作者Sami Al-Subhi
相关产品推荐
相关产品推荐

