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

Flutter跳转新页面前如何提前下载并缓存多个视频?

问题核心原因

你的现有方案存在两个致命问题,直接导致顺序混乱、加载失败甚至崩溃:

  • Dart中forEach不会等待内部异步函数执行完成,调用fetchFile时还没等所有视频缓存完毕,就会提前返回未完成的videos数组
  • 仅缓存视频文件没有预初始化播放器,哪怕是本地文件,首次创建播放器加载时仍会出现延迟,同时无校验的空数组传递也会引发空指针崩溃
修复方案

1. 修复批量缓存逻辑,保证顺序与完整性

使用Future.wait批量处理异步请求,它会严格按照输入的URL顺序返回缓存文件,且会等待所有缓存任务完成后再返回结果:

Future<List<File>> fetchVideos(List<String> urls) async {
  // 输出顺序与输入URL顺序完全一致,所有任务完成后才返回
  final List<File> cachedFiles = await Future.wait(
    urls.map((url) => DefaultCacheManager().getSingleFile(url))
  );
  return cachedFiles;
}

2. 预初始化视频控制器实现零延迟播放

如果要完全消除播放延迟,不要只传递视频文件到播放页,跳转前直接预初始化所有视频播放器控制器,预加载视频首帧:

// 先获取所有已缓存的本地视频文件
final cachedVideos = await fetchVideos(videoUrls);
// 预初始化所有播放器控制器
List<VideoPlayerController> videoControllers = [];
for (var file in cachedVideos) {
  final controller = VideoPlayerController.file(file);
  // 等待控制器初始化完成,预加载视频资源
  await controller.initialize();
  // 可根据需求配置默认音量、循环模式等
  controller.setVolume(1);
  videoControllers.add(controller);
}
// 确认页面存活后再跳转,传递预加载完成的控制器
if (context.mounted) {
  Navigator.of(context).push(
    MaterialPageRoute(builder: (context) => LessonScreen(controllers: videoControllers))
  );
}

3. 播放页逻辑实现

直接使用预初始化的控制器,切换播放时无任何加载过程:

class LessonScreen extends StatefulWidget {
  final List<VideoPlayerController> controllers;
  const LessonScreen({super.key, required this.controllers});

  @override
  State<LessonScreen> createState() => _LessonScreenState();
}

class _LessonScreenState extends State<LessonScreen> {
  int currentPlayIndex = 0;

  @override
  void initState() {
    super.initState();
    // 进入页面直接播放第一个视频
    widget.controllers[currentPlayIndex].play();
  }

  // 点击按钮播放下一个
  void playNextVideo() {
    if (currentPlayIndex >= widget.controllers.length - 1) return;
    // 重置当前视频进度到开头,暂停释放播放资源
    widget.controllers[currentPlayIndex].pause();
    widget.controllers[currentPlayIndex].seekTo(Duration.zero);
    // 切换到下一个视频直接播放,无加载延迟
    currentPlayIndex++;
    widget.controllers[currentPlayIndex].play();
    setState(() {});
  }

  @override
  void dispose() {
    // 销毁页面时释放所有控制器,避免内存泄漏
    for (var controller in widget.controllers) {
      controller.dispose();
    }
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: AspectRatio(
          aspectRatio: widget.controllers[currentPlayIndex].value.aspectRatio,
          child: VideoPlayer(widget.controllers[currentPlayIndex]),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: playNextVideo,
        child: const Icon(Icons.skip_next),
      ),
    );
  }
}

可选优化:自定义缓存配置

如果默认缓存空间不足导致视频被自动清理,可以自定义缓存管理器调整缓存规则:

class CustomVideoCacheManager {
  static const cacheKey = 'shortVideoCache';
  static final CacheManager instance = CacheManager(
    Config(
      cacheKey,
      stalePeriod: const Duration(days: 7), // 缓存有效期7天
      maxNrOfCacheObjects: 200, // 最多缓存200个视频文件
    ),
  );
}

使用时替换原有代码中的DefaultCacheManager()为CustomVideoCacheManager.instance即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 04:45:04