Flutter:setState()在封闭函数返回之前不会执行。
Flutter:setState()在封闭函数返回之前不会执行。
所以我在Flutter中尝试了这段代码:
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State
int _i = 1;
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: MaterialButton(
child: Text('You Pressed Me $_i'),
onPressed: () {
setState(() {
_i++;
print('inside i = $_i');
});
sleep(Duration(seconds: 10));
_i++;
print('outside i = $_i');
}
),
),
),
);
}
}
期望的行为(运行并按下按钮后):按钮显示文本"你按了我2次",然后变量_i增加到3,但不影响视觉结果。
实际行为:执行setState(),然后_i再次增加,但没有视觉变化,即屏幕上的文本不会更新,当onPressed()返回时,setState()导致小部件重建并更新屏幕,10秒后屏幕上显示的是"你按了我3次"。
关于setState(),文档中有这样一句话:
提供的回调立即同步调用。它不能返回一个future(回调不能是异步的),因为这样就不清楚何时实际设置状态。
我理解这个调用是同步的(根据这个答案,它是阻塞的),所以它应该先返回(这已经发生了),然后更新屏幕(或计划在将来某个时间进行),然后返回控制给后续行(后两个步骤都没有发生)。
我甚至尝试了没有sleep的情况,但结果相同。
那么我错过了什么或者误解了什么?
Flutter中的setState()方法不会在封闭函数返回之前执行的问题是由以下原因引起的:setState()方法会立即运行传递的函数,并且只是将小部件标记为"dirty",而不会直接操作状态。解决方法是使用WidgetsBinding.instance.addPostFrameCallback()方法,在小部件重建之后运行代码。
具体来说,当调用setState()时,传递的闭包函数会立即执行,并且会将小部件标记为"dirty",但不会直接修改状态。在示例中,尽管闭包函数将状态s设置为"1",但在闭包函数之后,该状态又被修改为"2"。因此,状态s的最终结果是"2"。
解决这个问题的方法是在闭包函数之外直接更新状态。这样,闭包函数只负责将小部件标记为"dirty",而不会修改状态。
另一种解决方法是手动处理StatefulWidget的元素创建,并手动标记它。但是,这种方法并不推荐使用。
为了在小部件重建之后运行代码,可以使用addPostFrameCallback()方法。具体实现请参考以下示例代码:
class _MyWidgetState extends State
String s = "";
onPressed: () {
this.s = "1";
setState(() {
// Implementation of setState calls
// _element.markNeedsBuild();
});
}
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
// doStuffAfterNextBuild
});
}
// Widget build()...
}
通过将要在小部件重建之后运行的代码放在addPostFrameCallback()的回调函数中,可以确保代码在小部件重建之后执行。
总之,setState()方法不会在封闭函数返回之前执行,这是由于其立即执行传递的闭包函数并将小部件标记为"dirty"。为了在小部件重建之后运行代码,可以使用addPostFrameCallback()方法。
Flutter中的setState()方法是用于更新widget状态的。然而,有一个问题是,setState()方法并不会立即执行,而是在包含它的函数返回后才执行。
这个问题的原因是Flutter中的事件循环(Event Loop)的存在。事件循环按顺序处理事件,而setState()方法是一个事件。下面是一个事件循环中的示例:
1. 事件A:用户点击触发的事件
2. 事件B:操作系统提供的Vsync信号
在上述示例中,事件A中包含了一个点击事件处理函数,其中调用了setState()方法。然而,该方法并不会立即执行,而是在函数返回后才执行。这是因为事件循环会按顺序处理事件,而setState()方法是一个事件,必须等待其他事件处理完成后才能执行。
为了解决这个问题,可以使用PostFrameCallback来在widget构建完成后执行任务。可以使用以下代码来添加一个PostFrameCallback:
WidgetsBinding.instance.addPostFrameCallback((_) {
// 在构建完成后执行任务
});
通过使用PostFrameCallback,可以在widget构建完成后执行一些任务,以解决setState()方法执行延迟的问题。
希望通过上述内容的整理,对Flutter中setState()方法不会立即执行的原因以及解决方法有了更清晰的理解。