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

Flutter:如何从嵌套类实时更新ProgressBar进度

问题描述

我希望从嵌套类中更新进度条数值,将回调函数传入foo方法后,期望计数器每次循环时都能通过setState()更新进度条。但实际情况是进度条仅在foo函数完全执行完毕后才会更新,我推测问题出在事件循环机制上。

主页面代码

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  double _progressBarVal = 0;
  final Counter _counter = Counter();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(
        children: [
          TextButton(
            onPressed: () {
              _counter.foo((val) {
                setState(() {
                  _progressBarVal = val;
                });
              });
            },
            child: const Text('Press me'),
          ),
          LinearProgressIndicator(
            value: _progressBarVal,
          ),
        ],
      ),
    );
  }
}

Counter类代码

class Counter {
  void foo(Function(double val) barCallback) {
    for (int i = 0; i <= 10; ++i) {
      barCallback(i / 10);
      debugPrint('Val is ${i / 10}');
      sleep(const Duration(seconds: 1));
    }
  }
}
解决方案

问题根源在于sleep(const Duration(seconds: 1))会阻塞Flutter的主线程,而UI渲染、setState触发的页面重建都依赖主线程的事件循环。主线程被阻塞时,所有UI更新操作都会被积压,直到foo函数的循环完全结束才会一次性执行。

要解决这个问题,需要将阻塞式的sleep替换为非阻塞的异步延迟,同时把foo方法改为异步函数:

修改后的Counter类

class Counter {
  Future<void> foo(Function(double val) barCallback) async {
    for (int i = 0; i <= 10; ++i) {
      barCallback(i / 10);
      debugPrint('Val is ${i / 10}');
      // 用非阻塞的异步延迟替代阻塞式sleep
      await Future.delayed(const Duration(seconds: 1));
    }
  }
}

主页面调用调整(更规范的写法)

在TextButton的onPressed中添加async,确保异步函数正确执行:

TextButton(
  onPressed: () async {
    await _counter.foo((val) {
      setState(() {
        _progressBarVal = val;
      });
    });
  },
  child: const Text('Press me'),
),

原理说明

Future.delayed会将延迟后的操作放入事件队列,await会让当前函数暂停执行,把控制权交回主线程的事件循环,这样UI渲染任务就能被及时处理,每次调用setState后进度条都会立刻更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 08:01:27