You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter点击抽屉导航项后fijkplayer视频无法切换播放

问题根因
  • StreamBuilder的builder函数会在组件每次重建时执行,在此处直接调用startPlay会导致播放逻辑被重复触发,且build阶段执行异步方法不符合Flutter生命周期规范
  • 调用setDataSource切换视频前没有重置播放器状态,fijkplayer在已持有播放源的状态下直接设置新源不会触发加载
  • 没有做URL变更判断,重复传入相同地址时会反复触发无效的设置逻辑,进一步扰乱播放器状态
修复方案
  1. 改造播放方法,切换源前先重置播放器状态,清空旧数据源:
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");
  });
}
  1. 将播放触发逻辑从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);
    }
  });
}
  1. 简化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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 12:51:24