从事原生开发的人,对生命周期并不陌生。很多交互都离不开生命周期,比如页面每次可见时开启定时器,不可见时停止定时器。本篇文章不做深入的流程分析,算是一篇总结性的文章,主要介绍生命周期的方法以及如何使用。
生命周期的图示如下
可以看到,State 的生命周期可以分为 3 个阶段:创建(插入视图树)、更新(在视图树中存在)、销毁(从视图树中移除)。
创建
State 初始化时会依次执行 :构造方法 -> initState
-> didChangeDependencies
-> build
,随后完成页面渲染。
- 构造方法是 State 生命周期的起点,Flutter 会通过调用 StatefulWidget.createState() 来创建一个 State。我们可以通过构造方法,来接收父 Widget 传递的初始化 UI 配置数据。这些配置数据,决定了 Widget 最初的呈现效果。
initState
,会在 State 对象被插入视图树的时候调用。这个函数在 State 的生命周期中只会被调用一次,所以我们可以在这里做一些初始化工作,比如为状态变量设定默认值。**didChangeDependencies**
则用来专门处理 State 对象依赖关系变化,会在 initState() 调用结束后,被 Flutter 调用。build
,作用是构建视图。经过以上步骤,Framework 认为 State 已经准备好了,于是调用 build。我们需要在这个函数中,根据父 Widget 传递过来的初始化配置数据,以及 State 的当前状态,创建一个 Widget 然后返回。
更新
Widget 的状态更新,主要由 3 个方法触发:setState
、didchangeDependencies
与 didUpdateWidget
。
**setState**
:我们最熟悉的方法之一。当状态数据发生变化时,我们总是通过调用这个方法告诉 Flutter:“我这儿的数据变啦,请使用更新后的数据重建 UI!”didChangeDependencies
:State 对象的依赖关系发生变化后,Flutter 会回调这个方法,随后触发组件构建。哪些情况下 State 对象的依赖关系会发生变化呢?这个“依赖”指的就是子widget是否使用了父widget中InheritedWidget的数据!如果使用了,则代表子widget依赖有依赖InheritedWidget;如果没有使用则代表没有依赖。这种机制可以使子组件在所依赖的InheritedWidget变化时来更新自身!比如当主题、locale(语言)等发生变化时,依赖其的子widget的didChangeDependencies方法将会被调用。didUpdateWidget
:当 Widget 的配置发生变化时,比如,父 Widget 触发重建(即父 Widget 的状态发生变化时),热重载时,系统会调用这个函数。一旦这三个方法被调用,Flutter 随后就会销毁老 Widget,并调用 build 方法重建 Widget。
想要获取或者监听APP在前台或者后台可以使用WidgetsBindingObserver
,这个类中有如下这些回调
abstract class WidgetsBindingObserver {
//页面pop
Future<bool> didPopRoute() => Future<bool>.value(false);
//页面push
Future<bool> didPushRoute(String route) => Future<bool>.value(false);
//系统窗口相关改变回调,如旋转
void didChangeMetrics() { }
//文本缩放系数变化
void didChangeTextScaleFactor() { }
//系统亮度变化
void didChangePlatformBrightness() { }
//本地化语言变化
void didChangeLocales(List<Locale> locale) { }
//App生命周期变化
void didChangeAppLifecycleState(AppLifecycleState state) { }
//内存警告回调
void didHaveMemoryPressure() { }
//Accessibility相关特性回调
void didChangeAccessibilityFeatures() {}
}
如果只监听前后台的话,可以通过didChangeAppLifecycleState
来进行,这个state主要有四种状态
- resumed:可见的,并能响应用户的输入。
- inactive:处在不活动状态,无法处理用户响应。
- paused:不可见并不能响应用户的输入,但是在后台继续活动中。
- detached: 它可以是在引擎首次初始化时附加视图的过程中,也可以是在视图由于导航器而被破坏之后
通常会在initState方法中添加监听,在dispose方法中解除监听,示例代码如下
class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver{
...
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);//注册监听器
}
@override
void dispose(){
super.dispose();
WidgetsBinding.instance.removeObserver(this);//移除监听器
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) async {
print("$state");
if (state == AppLifecycleState.resumed) {
//do sth
}
}
}
如果想要实现类似Android中的View.post
功能,可以使用
WidgetsBinding.instance.addPostFrameCallback((_){
print("单次Frame绘制回调");//只回调一次
});
如果有多个页面注册了前后台监听,比如A打开了B且A没关闭。A与B都注册了监听。这时候如果退到后台这两个页面都会受到通知
如果从后台回来
© 版权声明
文章版权归作者所有,未经允许请勿转载,侵权请联系 admin@trc20.tw 删除。
THE END