生命周期
理解 StatefulWidget 的生命周期,是写出正确、高效 Flutter 代码的关键。
生命周期流程图
┌──────────────┐
创建 Widget │ createState │
────────────► │ │
└──────┬───────┘
│
▼
┌──────────────┐
│ initState │ ← 只调用一次
│ (初始化) │
└──────┬───────┘
│
▼
┌──────────────────┐
│didChangeDependencies│ ← 依赖变化时
└──────┬───────────┘
│
┌────────────┴────────────┐
▼ ▼
┌────────────┐ ┌─────────────┐
│ build │◄─────────│ didUpdateWidget │
│ (构建UI) │ 属性变化 │ (属性更新时) │
└──────┬─────┘ └─────────────┘
│
▼
┌────────────┐ setState()
│ build │◄──────────
│ (重建UI) │ 状态变化
└──────┬─────┘
│
▼
┌────────────┐
│ deactivate │ ← 从树中移除(可能被重新插入)
└──────┬─────┘
│
被丢弃? ── 是 ──► ┌──────────┐
│ │ dispose │ ← 永久销毁
否 └──────────┘
│
└─── 重新插入树 ──► 回到 build()各阶段详解
initState()
dart
@override
void initState() {
super.initState();
// ✅ 在这里做初始化工作
_controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 1),
);
_loadData();
}适用场景:
- 初始化控制器(AnimationController、TextEditingController、ScrollController)
- 初始化状态变量的初始值
- 订阅事件流(Stream)
- 发起首次网络请求
- 添加监听器
注意:
- 不能在这里调用
BuildContext相关方法(如Theme.of(context)),此时 context 还未完全就绪 - 需要 context 的初始化操作请放在
didChangeDependencies()中
didChangeDependencies()
dart
@override
void didChangeDependencies() {
super.didChangeDependencies();
// ✅ 在这里使用 context 依赖的值
final size = MediaQuery.of(context).size;
final theme = Theme.of(context);
}适用场景:
- 获取
MediaQuery、Theme、InheritedWidget的值 - 当这些依赖发生变化时会重新调用
build()
dart
@override
Widget build(BuildContext context) {
return Container(
child: Text('count: $_count'),
);
}适用场景:
- 根据当前状态构建 UI
- 每次
setState()后都会被调用 - 尽量保持纯函数,避免副作用
didUpdateWidget()
dart
@override
void didUpdateWidget(covariant MyWidget oldWidget) {
super.didUpdateWidget(oldWidget);
// ✅ 父 Widget 传入新属性时的处理
if (widget.value != oldWidget.value) {
_controller.animateTo(widget.value);
}
}适用场景:
- 当父组件传入的属性变化时,同步更新内部状态
- 比较新旧属性
widget.xxx != oldWidget.xxx
deactivate()
dart
@override
void deactivate() {
super.deactivate();
// 通常不需要做什么
}说明:
- 当 State 对象从 Widget 树中移除时调用
- 可能会被重新插入(比如从一个位置移到另一个位置)
- 通常不需要重写这个方法
dispose()
dart
@override
void dispose() {
// ✅ 必须释放所有资源!
_controller.dispose();
_textEditingController.dispose();
_scrollController.dispose();
_subscription.cancel();
super.dispose();
}适用场景:
- 释放所有控制器(AnimationController、TextEditingController 等)
- 取消订阅(StreamSubscription、ChangeNotifier)
- 取消定时器
- 移除监听器
重要
忘记调用 dispose() 会导致内存泄漏!只要在 initState() 中创建/订阅了资源,就必须在 dispose() 中释放/取消。
常见模式
带网络请求的 Widget
dart
class UserList extends StatefulWidget {
const UserList({super.key});
@override
State<UserList> createState() => _UserListState();
}
class _UserListState extends State<UserList> {
List<User> _users = [];
bool _isLoading = true;
@override
void initState() {
super.initState();
_fetchUsers(); // 初始化时加载数据
}
Future<void> _fetchUsers() async {
try {
final users = await ApiService.getUsers();
setState(() {
_users = users;
_isLoading = false;
});
} catch (e) {
setState(() => _isLoading = false);
}
}
@override
Widget build(BuildContext context) {
if (_isLoading) {
return const CircularProgressIndicator();
}
return ListView.builder(
itemCount: _users.length,
itemBuilder: (context, index) {
return ListTile(title: Text(_users[index].name));
},
);
}
}带动画的 Widget
dart
class FadeIn extends StatefulWidget {
const FadeIn({super.key, required this.child});
final Widget child;
@override
State<FadeIn> createState() => _FadeInState();
}
class _FadeInState extends State<FadeIn> with SingleTickerProviderStateMixin {
late final AnimationController _controller;
late final Animation<double> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this, // SingleTickerProviderStateMixin 提供 vsync
duration: const Duration(milliseconds: 500),
);
_animation = CurvedAnimation(
parent: _controller,
curve: Curves.easeIn,
);
_controller.forward(); // 启动动画
}
@override
void dispose() {
_controller.dispose(); // 释放控制器
super.dispose();
}
@override
Widget build(BuildContext context) {
return FadeTransition(
opacity: _animation,
child: widget.child,
);
}
}