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
相关产品推荐
相关产品推荐

