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

Flutter如何高效实现无间断自动顺序播放视频?onComplete仅触发一次

问题根因
  • 你的MyVideoPlayer仅在首次初始化时给controller绑定了播放完成监听,后续_playVideo方法每次创建新的VideoPlayerController实例后,没有给新实例绑定对应完成监听,因此后续视频播放结束后不会触发onComplete回调
  • 旧controller没有执行销毁操作,存在内存泄漏风险,同时冗余的重复监听逻辑也可能引发状态判断冲突
修复方案
  1. 调整MyVideoPlayer的实现,将controller作为入参传入,同时在didUpdateWidget生命周期中处理controller更新后的监听重新绑定,增加销毁逻辑释放资源
class MyVideoPlayer extends StatefulWidget {
  const MyVideoPlayer({
    Key? key,
    required this.controller,
    required this.onComplete,
  }) : super(key: key);

  final VideoPlayerController controller;
  final VoidCallback onComplete;

  @override
  MyVideoPlayerState createState() => MyVideoPlayerState();
}
class MyVideoPlayerState extends State<MyVideoPlayer> {
  late VoidCallback _listener;

  @override
  void initState() {
    super.initState();
    _bindListener();
  }

  @override
  void didUpdateWidget(covariant MyVideoPlayer oldWidget) {
    super.didUpdateWidget(oldWidget);
    // controller更新时解绑旧监听,绑定新监听
    if (oldWidget.controller != widget.controller) {
      oldWidget.controller.removeListener(_listener);
      _bindListener();
    }
  }

  void _bindListener() {
    _listener = () {
      final value = widget.controller.value;
      if (!value.isPlaying && value.position >= value.duration) {
        widget.onComplete();
      }
    };
    widget.controller.addListener(_listener);
  }

  @override
  void dispose() {
    widget.controller.removeListener(_listener);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return VideoPlayer(widget.controller);
  }
}
  1. 调整主逻辑,维护播放列表索引,播放下一个视频前先销毁旧的controller,避免资源泄漏
// 示例为StatefulWidget的主页面,需要维护播放列表、当前索引、controller状态
class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  // 替换为你的实际视频资源列表
  final List<String> _videoAssets = ['video1.mp4', 'video2.mp4', 'video3.mp4'];
  int _currentIndex = 0;
  VideoPlayerController? _controller;

  @override
  void initState() {
    super.initState();
    _playCurrentVideo();
  }

  @override
  void dispose() {
    _controller?.dispose();
    super.dispose();
  }

  void _playCurrentVideo() {
    if (_currentIndex >= _videoAssets.length) return; // 全部播放完成的逻辑可自行补充
    // 先销毁旧controller释放资源
    _controller?.dispose();
    // 创建新controller
    _controller = VideoPlayerController.asset(_videoAssets[_currentIndex]);
    // 初始化完成后自动播放
    _controller!.initialize().then((_) {
      if (mounted) {
        setState(() {});
        _controller!.play();
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    if (_controller == null || !_controller!.value.isInitialized) {
      return const SizedBox(); // 加载占位组件可自行替换
    }
    return MyVideoPlayer(
      controller: _controller!,
      onComplete: () {
        // 播放完成后索引+1,播放下一个视频
        _currentIndex++;
        _playCurrentVideo();
        if (mounted) setState(() {});
      },
    );
  }
}
优化说明
  • 修正后每次更换视频都会给新的controller绑定播放完成监听,确保每个视频播放结束都会触发回调实现连续播放
  • 增加了controller的销毁逻辑,避免内存泄漏
  • 移除了冗余的重复监听逻辑,状态判断改为直接对比position和duration,避免了取整误差导致的判断失效问题

内容的提问来源于stack exchange,提问作者userRM

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 12:27:02