Flutter点击抽屉导航项后fijkplayer视频无法切换播放
问题根因
StreamBuilder的builder函数会在组件每次重建时执行,在此处直接调用startPlay会导致播放逻辑被重复触发,且build阶段执行异步方法不符合Flutter生命周期规范- 调用
setDataSource切换视频前没有重置播放器状态,fijkplayer在已持有播放源的状态下直接设置新源不会触发加载 - 没有做URL变更判断,重复传入相同地址时会反复触发无效的设置逻辑,进一步扰乱播放器状态
修复方案
- 改造播放方法,切换源前先重置播放器状态,清空旧数据源:
Future<void> startPlay(String newUrl) async { // 重置播放器到初始状态,停止当前播放、释放旧资源 await player.reset(); await player.setOption(FijkOption.hostCategory, "request-screen-on", 1); await player.setOption(FijkOption.hostCategory, "request-audio-focus", 1); await player.setDataSource(newUrl, autoPlay: true).catchError((e) { print("setDataSource error: $e"); }); }
- 将播放触发逻辑从
StreamBuilder的build方法中移走,在initState中监听导航流变化,仅当URL实际变更时才触发播放,避免build阶段执行异步逻辑:
// 记录当前播放地址,避免重复加载相同源 String _currentPlayUrl = ""; @override void initState() { super.initState(); player.setOption(FijkOption.hostCategory, "enable-snapshot", 1); player.setOption(FijkOption.playerCategory, "mediacodec-all-videos", 1); // 监听流事件触发播放 bloc.getNavigation.listen((newUrl) { if (newUrl != _currentPlayUrl && newUrl.isNotEmpty) { _currentPlayUrl = newUrl; startPlay(newUrl); } }); }
- 简化
StreamBuilder的渲染逻辑,仅负责组件渲染,不再处理播放触发逻辑:
body: StreamBuilder( stream: bloc.getNavigation, initialData: bloc.navigationProvider.currentNavigation, builder: (context, snapshot) { final currentUrl = snapshot.data.toString(); if (currentUrl.isNotEmpty) { return FijkView( player: player, panelBuilder: fijkPanel2Builder(snapShot: true), fsFit: FijkFit.fill, ); } return const Center(child: CircularProgressIndicator()); }, ),
补充:如果需要切换视频后自动关闭侧边抽屉,可以取消ListTile的onTap回调中
Navigator.of(context).pop()的注释。
内容的提问来源于stack exchange,提问作者Hide Mimin
相关产品推荐
相关产品推荐

