Flutter组件生命周期和App生命周期示例解析
作者:顾安 发布时间:2022-07-18 23:15:59
引言
在Flutter开发中,所有的组件和页面都继承自Widget,所以探索页面的生命周期其实就是Widget的生命周期。 在 Flutter 中一切皆 组件,而组件又分为 StatefulWidget(有状态) 和 StatelessWidget(无状态)组件
无状态组件(StatelessWidget)
无状态组件,可以理解为将外部传入的数据转化为界面展示的内容,只会渲染一次。
有状态组件(StatefulWidget)
有状态组件,是定义交互逻辑和业务数据,可以理解为具有动态可交互的内容界面,会根据数据的变化进行多次渲染。
StatefulWidget生命周期详细分析
1. createState
当StatefulWidget被创建时立即执行createState。createState 函数执行完毕后表示当前组件已经在 Widget 树中,此时有一个非常重要的属性mounted设置为true。
2. initState
该函数为 State 初始化调用,只会被调用一次。因此,通常会在该回调中做一些一次性的操作,如执行 State 各变量的初始赋值,获取服务端数据等。
3. didChangeDependencies
该函数是在该组件依赖的 State 发生变化时会被调用。didChangeDependencies 方法调用后,组件的状态变为 dirty,立即调用 build 方法。
4. build
主要是在方法中创建各种组件,绘制到屏幕上,由于 build 会被调用多次,因此在该函数中只能做返回 Widget 相关逻辑,避免因为执行多次而导致状态异常。因此此方法可以在每一帧中调用,此方法中应该只包含构建组件的代码,不应该包含其他额外的功能,尤其是耗时任务。
5. didUpdateWidget
该函数主要是在组件重新构建,比如说热重载,父组件发生 build 的情况下,子组件该方法才会被调用,其次该方法调用之后一定会再调用本组件中的 build 方法。此方法中通常会用当前组件与前组件进行对比。Framework 调用完此方法后,会将组件设置为 dirty 状态,然后调用 build 方法,因此无需在此方法中调用 setState 方法。
6. deactivate
在组件被移除节点后会被调用,在某些情况下,框架将重新插入 State 对象到树的其他位置(例如,如果包含该树的子树 State 对象从树中的一个位置移植到另一位置),框架将会调用 build 方法来提供 State 对象适应其在树中的新位置。
7. dispose
永久移除组件,并释放组件资源。调用完 dispose后,mounted 属性被设置为 false,也代表组件生命周期的结束,此时再调用 setState 方法将会抛出异常。
8. reassemble
主要在开发阶段使用,在 debug 模式下,每次热重载都会调用该函数,因此在 debug 阶段可以在此期间增加一些 debug 代码,来检查代码问题。
App生命周期
App的生命周期的监听,在Flutter中需要通过 * WidgetsBindingObserver * 中的AppLifecycleState方法来是实现。
class AppLifePage extends StatefulWidget {
CEAppLifePage({Key key}) : super(key: key);
@override
_AppLifePageState createState() => _AppLifePageState();
}
// 实现WidgetsBindingObserver观察者
class _AppLifePageState extends State<AppLifePage> with WidgetsBindingObserver{
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this); //添加观察者
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("App生命周期"),),
body: Text('Flutter App 生命周期'),
);
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
print("didChangeAppLifecycleState: $state");
switch (state) {
case AppLifecycleState.resumed:
print('应用程序可见且响应用户输入。');
break;
case AppLifecycleState.paused:
print('应用程序不可见且无法响应用户输入,运行在后台。');
break;
case AppLifecycleState.inactive:
print('应用程序处于非激活状态,无法响应用户输入。');
break;
case AppLifecycleState.detached:
print('应用程序仍寄存在Flutter引擎上,但与平台 View 分离。');
break;
}
}
// 当前系统改变了一些访问性活动的回调
@override
void didChangeAccessibilityFeatures() {
super.didChangeAccessibilityFeatures();
print("didChangeAccessibilityFeatures");
}
// 低内存回调
@override
void didHaveMemoryPressure() {
super.didHaveMemoryPressure();
print("didHaveMemoryPressure");
}
// 用户本地设置变化时调用,如系统语言改变
@override
void didChangeLocales(List<Locale> locale) {
super.didChangeLocales(locale);
print("didChangeLocales");
}
// 应用尺寸改变时回调,例如旋转
@override
void didChangeMetrics() {
super.didChangeMetrics();
Size size = WidgetsBinding.instance.window.physicalSize;
print("didChangeMetrics :宽:${size.width} 高:${size.height}");
}
// 系统切换主题时回调
@override
void didChangePlatformBrightness() {
super.didChangePlatformBrightness();
print("didChangePlatformBrightness");
}
// 文字系数变化
@override
void didChangeTextScaleFactor() {
super.didChangeTextScaleFactor();
print(
"didChangeTextScaleFactor :${WidgetsBinding.instance.window.textScaleFactor}");
}
@override
void dispose() {
super.dispose();
WidgetsBinding.instance.removeObserver(this); // 销毁观察者
}
}
重点是重写 didChangeAppLifecycleState 方法,AppLifecycleState 中的状态包括:resumed、inactive、paused、detached。
resumed:应用程序可见且响应用户输入。
inactive:应用程序处于非激活状态,无法响应用户输入。在iOS上,打电话、响应TouchID请求、进入应用程序切换器或控制中心都处于此状态。在Android上,分屏应用,打电话,弹出系统对话框或其他窗口等。
pause:应用程序不可见且无法响应用户输入,运行在后台。处于此状态时,引擎将不会调用 Window.onBeginFrame 和 Window.onDrawFrame。
detached:应用程序仍寄存在Flutter引擎上,但与平台 View 分离。处于此状态的时机:引擎首次加载到附加 到一个平台 View的过程中,或者由于执行 Navigator pop ,view 被销毁。
结束语
来源:https://juejin.cn/post/7168709152808648735


猜你喜欢
- 本文实例为大家分享了scrollView实现顶部图片下拉放大的具体代码,供大家参考,具体内容如下之前的scrollView顶部图片下拉放大在
- 同样该功能需要加载命名空间using System.Runtime.InteropServices;private const uint W
- 在日常开发的过程中应该不可避免的会发生 crash,无论你的程序写的多么完美,都不可能完全避免 crash 的发生,可能是由于 Androi
- 本文实例讲述了C#实现Xml序列化与反序列化的方法。分享给大家供大家参考。具体实现方法如下:/// <summary>/// X
- 本篇概览在检测人脸数量、位置、性别、口罩等场景时,可以考虑使用百度开放平台提供的web接口,一个web请求就能完成检测得到结果,本篇记录了从
- 1、需求 在Java项目中,需要读取resource资源目录下的文件,以及遍历指定资源目
- 如果我们在Intellij Idea中开发好程序,需要部署到远程SSH服务器运行,我们可以使用某些SSH软件的rz功能,也可以使用专用的FT
- 1. Mybatis的@param注解自定义对象也用@param注解注:使用@param注解,mapper.xml 不加parameterT
- 接口可以声明事件。 下面的示例演示如何在类中实现接口事件。 这些规则基本上都与实现任何接口方法或属性时的相同。在类中实现接口事件在类中声明事
- 之前使用springMVC+spring+mybatis,总是被一些繁琐的xml配置,有时候如果配置出错,还要检查各种xml配置,偶然接触到
- AndroidStudio 的SVN 安装和使用方法与我以前用的其他IDE 都有很大差别,感觉特麻烦,网上相关资料很少,貌似现在 Git 比
- 多亏了<include />标签,在Android里,很容易就能做到共享和重用UI组件。在Android开发中,很容易就能创建出
- PostgreSQL是一种特性非常齐全的自由软件的对象-关系型数据库管理系统(ORDBMS),是以加州大学计算机系开发的POSTGRES,4
- java 对象的克隆一、对象的浅克隆(1)需要克隆类需要重写Object类的clone方法,并且实现Cloneable接口(标识接口,无需实
- 有时候编译器、处理器的优化会导致runtime与我们设想的不一样,为此Java对编译器和处理器做了一些限制,JAVA内存模型(JMM)将这些
- 本文实例为大家分享了Android实现ListView下拉刷新上拉加载更多的具体代码,供大家参考,具体内容如下其实谷歌官方目前已经推出Lis
- Mybatis无法获取带有下划线前缀的字段的值今天下面,把几张表里的字段都加了前缀,如 article_id,article_title,a
- 目录开始准备开始动画画圆弧项目使用背景图完整代码今天介绍一个很简单的倒计时动画,仿酷狗音乐的启动页倒计时效果,也是大多数APP在用的一个动画
- 前言SQLite是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。它是一个零配置的数据库,这意味着与其
- 一、前言最近做的项目由于引入第三方库导致在运行mvn clean package 打jar时,编译出来的 Jar 包很大(服务器多达500M