开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 4 天,点击查看活动详情
1、State 生命周期
先引用一张图
再看源码
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
@override
Widget build(BuildContext context) {
debugPrint("build debug");
return Scaffold();
}
@override
void initState() {
// TODO: implement initState
super.initState();
debugPrint("init state");
}
@override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
super.didChangeDependencies();
debugPrint("did change dependencies");
}
@override
void activate() {
// TODO: implement activate
super.activate();
debugPrint("activate");
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
debugPrint("dispose");
}
@override
void deactivate() {
// TODO: implement deactivate
super.deactivate();
debugPrint("deactivate");
}
@override
void didUpdateWidget(covariant MyHomePage oldWidget) {
// TODO: implement didUpdateWidget
super.didUpdateWidget(oldWidget);
debugPrint("did update widget");
}
@override
void reassemble() {
// TODO: implement reassemble
super.reassemble();
debugPrint("reassemble");
}
State 生命周期是不是已经一目了然。下面简单介绍下各个方法的作用。
- initState(): 当widget 第一次插入到Widget树时会被调用,类似于iOS中的init 方法。每个State对象,只会调用一次。常做一些数据的初始化。
- didChangeDependencies(): 当State对象的依赖发生变化的时候会被调用。比如:Build()中包含Inherited Widget发生变化。此函数会被调用。系统风格或者语言改变时也会回调。
- build():构建Widget树时被调用。
- reassemble:开发调试热重载时调用。Release环境下不会被调用。
- didUpdateWidget():在Widget重新构建时会被调用。Flutter 框架会调用Widget.canUpdate来检测树中同一位置的新旧节点,判断是否需要更新。这里面设计到一个State的状态Dirty 和clear 状态,后面再了解。canUpdate是根据新旧widget的key和runtimeType 同时相等时返回True。
- deactivate():当State对象从树中被移除时,会调用此方法。比如在一些场景下,将State对象从一个位置移动到另外一个位置时(通过GlobalKey来实现)。如果移除后,没有插入到树中,则会调用dispose().
- dispose(): 当State对象从树中被永久移除时调用。类似于OC中的dealloc函数。
- activate():当State从树中移除后又重新插入到新的位置时会被调用。 大概顺序是:
(Parent)build——>deactivate——>activate——>didUpdateWidget——>(child)build
以上是Flutter 中State的生命周期。
2、APP 生命周期
了解了State的生命周期,那么就顺便了解APP的生命周期。
APP的生命周期是通过WidgetsBindingObserver类监听来实现状态获取。下面是WidgetsBindingObserver回调函数.
// Accessibility 相关特性回调
void didChangeAccessibilityFeatures() { }
// App 生命周期改变回调
void didChangeAppLifecycleState(AppLifecycleState state) { }
// 本地化语言改变回调
void didChangeLocales(List<Locale> locale) { }
// 系统窗口相关改变回调
void didChangeMetrics() { }
// 系统亮度改变回调
void didChangePlatformBrightness() { }
// 文本缩放系数改变回调
void didChangeTextScaleFactor() { }
// 内存不足警告回调
void didHaveMemoryPressure() { }
// 页面 pop
Future<bool> didPopRoute() => Future<bool>.value(false);
// 页面 push
Future<bool> didPushRoute(String route) => Future<bool>.value(false);
使用上面的函数回调,可对WidgetsBindingObserver单例对象设置监听。
class AppLifecycleReactor extends StatefulWidget {
const AppLifecycleReactor({ Key key }) : super(key: key);
@override
_AppLifecycleReactorState createState() => _AppLifecycleReactorState();
}
class _AppLifecycleReactorState extends State<AppLifecycleReactor> with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);// 注册监听器
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);// 移除监听器
super.dispose();
}
AppLifecycleState _notification;
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
print("$state");
}
}
- inactive:处在不活动状态,无法处理用户响应
- paused: 不可见且不能响应用户输入,但在后台继续活动中
- resumed: 可见的,且能响应用户的输入
切换前后台,观察控制台
- 从前台到后台,控制台打印的APP生命周期变化如下
AppLifecycleState.resumed->AppLifecycleState.inactive->AppLifecycleState.paused
- 从后台切换到前台,打印如下: AppLifecycleState.paused->AppLifecycleState.inactive->AppLifecycleState.resumed
3、帧绘制回调
在组件完成渲染后做的一些和显示相关的其他处理,比如现场切换,可以使用WidgetsBinding来实现。 WidgetsBinding提供了单词Frame绘制回调和实时 Frame绘制回调两种机制.
- 单词Frame绘制回调,通过addPistFrameCallback实现。在当前Frame绘制完成后进行回调,且只会回调一次,如果需要多次回调则手动设置。
WidgetsBindingObserver.instance.addPostFrameCallback((_){
print("addPostFrameCallback 绘制回调"); // 只回调一次
});
- 实时Frame绘制回调;通过addPersistertFrameCallback实现。在每次绘制Frame结束后,进行回调.
WidgetsBindingObserver.instance.addPersistentFrameCallback((_){
print("addPersistentFrameCallback 绘制回调"); // 每帧都回调
});