news 2026/4/20 22:04:14

Flutter的生命周期:Widget 生命周期、App 生命周期 和 路由生命周期

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Flutter的生命周期:Widget 生命周期、App 生命周期 和 路由生命周期

一、StatefulWidget 生命周期

这是 Flutter 中最常用、最重要的生命周期,每个StatefulWidget都有完整的生命周期流程。

1. 生命周期流程图

2. 生命周期方法

class MyWidget extends StatefulWidget { @override _MyWidgetState createState() => _MyWidgetState(); } class _MyWidgetState extends State<MyWidget> { // 1. 构造函数(不是生命周期方法,但最先执行) _MyWidgetState() { print('1. 构造函数执行'); } // 2. initState - 状态初始化 @override void initState() { super.initState(); print('2. initState - 只执行一次'); // 初始化数据、监听器、Stream、动画控制器等 // 注意:不能在这里调用 BuildContext 的依赖方法 } // 3. didChangeDependencies - 依赖变化时调用 @override void didChangeDependencies() { super.didChangeDependencies(); print('3. didChangeDependencies - 依赖的 InheritedWidget 变化时调用'); // 在 initState 之后立即调用,之后每次依赖变化都会调用 } // 4. build - 构建 UI @override Widget build(BuildContext context) { print('4. build - UI 构建'); return Container( child: Text('Hello'), ); } // 5. didUpdateWidget - Widget 配置更新时调用 @override void didUpdateWidget(covariant MyWidget oldWidget) { super.didUpdateWidget(oldWidget); print('5. didUpdateWidget - Widget 重建且配置变化时调用'); // 当父 Widget 重建并传递了新参数时调用 } // 6. setState - 触发重建(不是生命周期方法,但常用) void updateData() { setState(() { print('6. setState - 触发 UI 重建'); // 更新状态 }); } // 7. deactivate - 从树中移除时调用 @override void deactivate() { super.deactivate(); print('7. deactivate - State 从树中移除'); // 当 Widget 被移除(如路由返回)时调用 } // 8. dispose - 永久销毁 @override void dispose() { print('8. dispose - 永久销毁,释放资源'); // 取消监听器、销毁动画控制器、关闭 Stream 等 super.dispose(); } // 9. reassemble - 热重载时调用(仅开发环境) @override void reassemble() { super.reassemble(); print('9. reassemble - 热重载时调用'); } }

二、App 生命周期(WidgetsBindingObserver)

通过WidgetsBindingObserver可以监听应用的前后台切换、系统弹窗等。

1. 监听应用状态

class AppLifecycleDemo extends StatefulWidget { @override _AppLifecycleDemoState createState() => _AppLifecycleDemoState(); } class _AppLifecycleDemoState extends State<AppLifecycleDemo> with WidgetsBindingObserver { AppLifecycleState? _appLifecycleState; @override void initState() { super.initState(); // 添加观察者 WidgetsBinding.instance.addObserver(this); } @override void dispose() { // 移除观察者 WidgetsBinding.instance.removeObserver(this); super.dispose(); } @override void didChangeAppLifecycleState(AppLifecycleState state) { setState(() { _appLifecycleState = state; }); switch (state) { case AppLifecycleState.resumed: print('应用回到前台'); break; case AppLifecycleState.inactive: print('应用处于非活动状态(如接电话)'); break; case AppLifecycleState.paused: print('应用进入后台'); break; case AppLifecycleState.detached: print('应用即将被销毁'); break; case AppLifecycleState.hidden: print('应用隐藏(iOS 特有)'); break; } } @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Text('App 状态: $_appLifecycleState'), ), ); } }

三、路由生命周期

1. RouteObserver 监听路由变化

// 创建 RouteObserver final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>(); // 在 MaterialApp 中注册 class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( navigatorObservers: [routeObserver], // 注册观察者 home: HomePage(), ); } } // 使用 RouteAware 监听页面生命周期 class MyPage extends StatefulWidget { @override _MyPageState createState() => _MyPageState(); } class _MyPageState extends State<MyPage> with RouteAware { @override void didChangeDependencies() { super.didChangeDependencies(); // 订阅路由观察者 routeObserver.subscribe(this, ModalRoute.of(context) as PageRoute); } @override void dispose() { // 取消订阅 routeObserver.unsubscribe(this); super.dispose(); } // 页面被推入时调用 @override void didPush() { print('页面被推入'); } // 页面被弹出时调用 @override void didPop() { print('页面被弹出'); } // 页面被新的页面覆盖时调用 @override void didPushNext() { print('有新页面推入,当前页面被覆盖'); } // 覆盖当前页面的页面被弹出时调用 @override void didPopNext() { print('上面的页面被弹出,当前页面重新显示'); } @override Widget build(BuildContext context) { return Scaffold( body: Center(child: Text('路由生命周期示例')), ); } }

2. 使用 Navigator 观察者

class MyNavigatorObserver extends NavigatorObserver { @override void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) { print('推入路由: ${route.settings.name}'); } @override void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) { print('弹出路由: ${route.settings.name}'); } @override void didRemove(Route<dynamic> route, Route<dynamic>? previousRoute) { print('移除路由: ${route.settings.name}'); } @override void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute}) { print('替换路由: ${oldRoute?.settings.name} -> ${newRoute?.settings.name}'); } } // 使用 MaterialApp( navigatorObservers: [MyNavigatorObserver()], // ... )

四、KeepAlive 生命周期(AutomaticKeepAliveClientMixin)

用于保持页面状态,如 Tab 页切换时保持页面不被销毁。

class KeepAlivePage extends StatefulWidget { @override _KeepAlivePageState createState() => _KeepAlivePageState(); } class _KeepAlivePageState extends State<KeepAlivePage> with AutomaticKeepAliveClientMixin { int _counter = 0; @override bool get wantKeepAlive => true; // 保持页面状态 @override Widget build(BuildContext context) { // 必须调用 super.build super.build(context); return Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text('计数: $_counter'), ElevatedButton( onPressed: () { setState(() { _counter++; }); }, child: Text('增加'), ), ], ), ), ); } }

五、生命周期汇总

生命周期调用时机主要用途
createStateState 对象创建时创建 State 实例
initStateWidget 插入树后初始化数据、监听器、动画
didChangeDependencies依赖变化时处理 InheritedWidget 变化
build每次重建时构建 UI
didUpdateWidgetWidget 配置变化时响应父 Widget 参数变化
setState手动调用时触发 UI 重建
deactivateState 从树移除时临时移除前的清理
disposeState 永久销毁时释放资源、取消订阅
didChangeAppLifecycleState应用前后台切换暂停/恢复资源
didPush/didPop路由变化时页面埋点、状态管理

备注:

  1. dispose中释放所有资源(定时器、Stream、动画控制器)。

  2. 使用mounted检查 State 是否还在树中,避免在dispose后调用setState。

  3. 利用WidgetsBindingObserver监听应用状态,优化资源使用。

  4. 使用RouteObserver追踪页面访问,便于埋点和分析。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/20 22:04:13

Hyperf方案 跨地域多活架构

Hyperf 跨地域多活核心工具链&#xff1a; )┌──────────┬────────────────────────────┐│ 关注点 │ 方案 │ ├───…

作者头像 李华
网站建设 2026/4/20 22:03:16

Blazor + WASM + WebGPU 实时渲染面试突击包:含WebAssembly SIMD加速、GPU缓冲区绑定、帧同步调试全流程(仅限Q2开放下载)

第一章&#xff1a;C# Blazor 2026 现代 Web 开发趋势 面试题汇总随着 .NET 9 的正式发布与 WebAssembly 运行时性能的持续优化&#xff0c;Blazor 已成为构建高性能、全栈式 C# Web 应用的核心范式。2026 年面试官更关注开发者对服务端预渲染&#xff08;SSR&#xff09;、混合…

作者头像 李华
网站建设 2026/4/20 22:03:14

从战场到物流:拆解异构无人机集群的‘大脑’——任务规划核心模型与避坑要点

从战场到物流&#xff1a;拆解异构无人机集群的‘大脑’——任务规划核心模型与避坑要点 当你在山区看到无人机群精准投递医疗物资&#xff0c;或在万亩农田上空同步完成喷洒与监测时&#xff0c;背后是任务规划系统在实时处理数百个动态变量。这套系统正从军事领域快速渗透到民…

作者头像 李华
网站建设 2026/4/20 22:02:40

洛谷官方精选题单(C++版)

​欢迎大家订阅我的专栏&#xff1a;算法题解&#xff1a;C与Python实现&#xff01; 本专栏旨在帮助大家从基础到进阶 &#xff0c;逐步提升编程能力&#xff0c;助力信息学竞赛备战&#xff01; 专栏特色 1.经典算法练习&#xff1a;根据信息学竞赛大纲&#xff0c;精心挑选…

作者头像 李华
网站建设 2026/4/20 22:01:52

老旧电脑适合用哪种HTML函数工具_低配设备适配方法【方法】

老旧电脑HTML开发卡顿问题可通过四类方法解决&#xff1a;一、用Notepad旧版轻量编辑&#xff1b;二、在Firefox ESR中手动启用HTML5相关配置&#xff1b;三、使用免安装的HTML工具箱网页版&#xff1b;四、部署原生Win32的FirHtml图形化编辑环境。如果您在老旧电脑上编辑或预览…

作者头像 李华
网站建设 2026/4/20 21:54:36

PDO Error Handling: Exceptions vs ErrorInfo with PHP

When interacting with databases using PHP’s PDO extension, robust error management is crucial for building reliable applications. This often involves deciding between PDO’s exception mode or utilizing the errorInfo() method. Let’s delve into the nuances…

作者头像 李华