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

Flutter双Widget异步任务同步执行问题求助

问题分析

你当前的代码存在几个问题导致左右列表下载速度差异大:

  1. 构造函数、函数名不匹配(MainList的构造写成了TemplatesList,_List的构造写成了MemeList;initState里调用downloadPreviews,但定义的是downloadFiles),这些语法错误会导致代码无法正常运行。
  2. 核心问题是两个_List组件各自独立启动下载,且downloadFiles的实现有问题:使用forEach遍历异步操作时,forEach无法保证任务并行执行的效率,加上左侧列表可能先完成组件初始化,导致整体下载进度左侧更快。
解决方案

要实现左右列表的文件同时下载,有两种可行方案:

方案一:统一管理所有下载任务(推荐)

将下载逻辑从子组件_List移到父组件MainList(改为StatefulWidget),统一启动所有文件的并行下载,再将下载状态传递给两个子列表。

修正后的完整代码:

class MainList extends StatefulWidget {
  final List<TemplateData> list;

  const MainList({required this.list, super.key});

  @override
  State<MainList> createState() => _MainListState();
}

class _MainListState extends State<MainList> {
  late List<bool> fileDownloaded;

  @override
  void initState() {
    super.initState();
    fileDownloaded = widget.list.map((e) => false).toList();
    downloadAllFiles();
  }

  Future downloadAllFiles() async {
    // 同时启动所有文件的下载任务,并行执行
    await Future.wait(widget.list.map((file) async {
      await downloadFile(file);
      setState(() {
        fileDownloaded[widget.list.indexOf(file)] = true;
      });
    }));
  }

  @override
  Widget build(BuildContext context) {
    final int index = (widget.list.length / 2).round();
    final listLeft = widget.list.sublist(0, index);
    final listRight = widget.list.sublist(index);

    return SingleChildScrollView(
      child: Padding(
        padding: const EdgeInsets.all(8),
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Flexible(child: _List(
              templateData: listLeft,
              downloadStates: fileDownloaded.sublist(0, index),
            )),
            Flexible(child: _List(
              templateData: listRight,
              downloadStates: fileDownloaded.sublist(index),
            )),
          ],
        ),
      ),
    );
  }
}

class _List extends StatelessWidget{
  final List<TemplateData> templateData;
  final List<bool> downloadStates;

  const _List({required this.templateData, required this.downloadStates, super.key});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        for (int i = 0; i < templateData.length; i++) 
          MyItem(
            name: templateData[i].name, // 根据TemplateData结构调整属性
            is_downloaded: downloadStates[i],
          ),
      ],
    );
  }
}

方案二:修正子组件的下载逻辑

如果要保持子组件独立管理下载,需要确保每个_List的下载任务真正并行,并且两个子组件的下载同时启动。

修正后的_List相关代码:

class _List extends StatefulWidget{
  final List<TemplateData> templateData;

  const _List({required this.templateData, super.key});

  @override
  State<_List> createState() => _ListState();
}

class _ListState extends State<_List>{
  late List<bool> fileDownloaded;

  @override
  void initState() {
    super.initState();
    fileDownloaded = widget.templateData.map((e) => false).toList();
    downloadFiles();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        for (int i = 0; i < widget.templateData.length; i++) 
          MyItem(
            name: widget.templateData[i].name, // 根据TemplateData结构调整属性
            is_downloaded: fileDownloaded[i],
          ),
      ],
    );
  }

  Future downloadFiles() async {
    // 使用Future.wait同时启动所有下载任务,并行执行
    await Future.wait(widget.templateData.map((file) async {
      await downloadFile(file);
      final index = widget.templateData.indexOf(file);
      setState(() {
        fileDownloaded[index] = true;
      });
    }));
  }
}
关键说明
  • 原代码中forEach遍历异步操作时,无法保证任务并行执行的效率,改用Future.wait可以同时启动所有异步任务,真正实现并行下载。
  • 方案一的优势在于统一管理所有下载状态,避免子组件各自维护状态的冗余,也能确保所有文件(无论左右列表)同时开始下载,彻底解决左右进度差异的问题。
  • 注意根据你的TemplateData结构调整MyItem的name参数(比如取file.name),原代码存在类型不匹配的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 07:25:35