代码
class _SplashPageState extends State<SplashPage> {
final int duration = 10;
int number = 0;
// 倒计时
Future<void> _countdown() async {
number = duration;
// initState 方法只会执行一次,我刚开始没有用循环,我以为setState刷新页面之后,又会执行setState
for (int i = 0; i < duration; i++) {
await Future.delayed(const Duration(seconds: 1), () {
// mounted 这个值是用来判断当前状态对象是否仍然在树中
// flutter 分配完你的组件树位置,会设置 mounted 为 true。
// 如果 mounted 为 false,说明组件已经被从树中移除
// mounted 是在什么时候被赋值为true的? 是在initState中
if (mounted == true) {
setState(() {
print("setState: $number");
number--;
});
}
});
// 倒计时结束, 进入 welcome
if (number == 0) {
// 这里不再调用setState方法,就不会再刷新页面
print("倒计时结束");
}
}
}
@override
void initState() {
super.initState();
// 启动倒计时
_countdown();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.backgroundSplash,
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
//.................这里省略代码.....................
const SizedBox(height: 27),
Text(
number > 0 ? "$number" : "done",
style: TextStyle(
fontSize: 19,
fontFamily: 'Poppins',
fontWeight: FontWeight.bold,
color: Colors.white,
height: 22 / 19,
),
),
],
),
),
);
}
}

// 日志:
I/flutter (11576): setState: 10
D/InsetsController(11576): hide(ime(), fromIme=false)
I/ImeTracker(11576): com.example.flutter_quickstart_learn:ce680350: onCancelled at PHASE_CLIENT_ALREADY_HIDDEN
I/flutter (11576): setState: 9
I/flutter (11576): setState: 8
I/flutter (11576): setState: 7
I/flutter (11576): setState: 6
I/flutter (11576): setState: 5
I/flutter (11576): setState: 4
I/flutter (11576): setState: 3
I/flutter (11576): setState: 2
I/flutter (11576): setState: 1
I/flutter (11576): 倒计时结束
setState()
里只放最小必要的状态更新,而不是流程逻辑。
我犯的错误:
setState(() async {
await Future.delayed(Duration(seconds: 1));
counter--;
});
为什么不建议在 setState()
里写复杂逻辑?
影响可读性:
setState()
的职责应该很单一:修改状态并触发重建。如果里面塞了大量逻辑(比如网络请求、延时、计算),别人看代码时很难一眼看出哪个是 UI 状态的变更。异步问题:在
setState()
里直接写await
或Future.delayed
,容易出现 状态更新过晚 或 Widget 已经销毁还在更新 的问题。setState(() async { await Future.delayed(Duration(seconds: 1)); counter--; });
这样写会报错:
setState() callback argument returned a Future
。性能问题:大量逻辑放在
setState()
里会导致 UI 重建的范围扩大,增加不必要的渲染。
正确写法:把耗时/逻辑操作写在外面,只在 setState()
里更新数据:
Future<void> increaseLater() async {
await Future.delayed(Duration(seconds: 1));
if (mounted) { // 确保页面还在
setState(() {
counter--;
});
}
}