点击上方蓝字关注我,知识会给你力量
了解Flutter的生命周期,是我们写出优雅的App的基石,通过生命周期的适配,可以让代码更加稳健,鲁棒性更好。
Widget生命周期
下面这张图,就展示了一个Widget的整体生命周期示例。
当你把BuildContext分配给Widget时,一个内部标志位—mounted会被设置为true。这会让Framework知道这个Widget目前已经挂载到Widget Tree上。下面我们分三个方面来看下Widget生命周期的处理过程。
创建
Widget会依次经历initState->didChangeDependencies->build三个过程。
initState()是一个Widget被创建后调用的第一个方法。这类似于Android的onCreate()或iOS的viewDidLoad()方法。
在Framework第一次构建一个Widget时,它会在initState()之后调用didChangeDependencies()方法。如果你的Widget state依赖于一个InheritedWidget,它可能会再次调用didChangeDependencies()。
最后,框架在didChangeDependencies()之后调用build()方法。这个方法对开发者来说是最重要的,因为每次有Widget需要渲染时,都会调用这个方法。Widget Tree上的每个Widget都会递归地触发build()方法,所以这个方法内部的操作必须非常快。
❝所以,你应该总是将繁重的计算功能异步执行,并将其结果存储为state的一部分,以便后面与build()方法一起使用。build()方法不应该做任何有计算要求的事情。这类似于你对iOS或Android主线程的概念,例如,你不应该在主线程请求一个网络调用,这样使UI渲染停滞。
❞
更新
Widget在更新时,主要会经历setState->didchangeDependencies->didUpdateWidget三个过程。
每当你想修改你的Widget的状态时,你可以调用setState()方法。然后Framework会将该Widget标记为「dirty」,并再次触发build()方法。
❝异步代码应该总是在调用setstate()之前,检查mounted属性是否为true,因为该Widget在异步执行后,可能不再是Widget Tree的一部分来了。
❞
当父Widget change时或需要重新绘制用户界面时,或者是热重载时,框架会调用didUpdateWidget方法。当这种情况发生时,你会得到oldWidget实例作为参数,这样你就可以把它和你当前的widget进行比较,并做任何额外的逻辑。
当State对象的依赖关系发生改变时,例如系统Local或者Theme发生改变时,Framework就会回调didChangeDependencies方法。
一旦这些方法被调用,Framework就会销毁Old Widget,并执行新的Widget的build方法。
销毁
当你从Widget Tree中移除对象时,Framework会调用deactivate()方法。在某些情况下,Framework可以将state对象重新插入到Widget Tree的另一部分。
当你从Widget Tree上永久地移除某个Widget及其state时,框架会调用dispose()方法。这个方法非常重要,因为你需要它来清理内存,比如取消订阅流和处理动画或控制器。
❝在dispose()方法中,你应该检查你在state中定义的任何属性,并确保你已经正确处置了它们。
❞
App生命周期
前面我们分析了Widget的生命周期,而对于App来说,它的生命周期则更复杂一些。在Android中,我们通常需要处理onCreate、onPause、onResume这些生命周期回调方法,而在Flutter中,我们可以通过WidgetsBindingObserver来实现生命周期的监听。
didChangeAppLifecycleState
didChangeAppLifecycleState是App生命周期的回调方法,它提供了AppLifecycleState的枚举:
resumed:可见的,并能响应用户的输入。
inactive:处在不活动状态,无法处理用户响应。
paused:不可见并不能响应用户的输入,但是在后台继续活动中。
class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
@override
void initState() {
WidgetsBinding.instance.addObserver(this);
super.initState();
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
print('didChangeAppLifecycleState $state');
super.didChangeAppLifecycleState(state);
}
@override
Widget build(BuildContext context) {
return const CommonPage();
}
}
当我们退到后台时:
didChangeAppLifecycleState AppLifecycleState.inactive
didChangeAppLifecycleState AppLifecycleState.paused
再回到前台时:
didChangeAppLifecycleState AppLifecycleState.resumed
帧渲染完成回调
Flutter对帧的绘制回调进行了封装,通过WidgetsBinding,我们可以很方便的获取单次的帧绘制回调和实时的帧绘制回调。
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {});
WidgetsBinding.instance.addPersistentFrameCallback((timeStamp) {});
通过这两个回调,我们既可以获取单次的Frame渲染完成的节点,也可以获取每次渲染完成的节点,从而实现FPS的监听。
向大家推荐下我的网站 https://www.yuque.com/xuyisheng 点击原文一键直达
专注 Android-Kotlin-Flutter 欢迎大家访问
往期推荐
本文原创公众号:群英传,授权转载请联系微信(Tomcat_xu),授权后,请在原创发表24小时后转载。
< END >
作者:徐宜生
更文不易,点个“三连”支持一下👇