阅读 333

Flutter实战之生命周期篇

前言

Flutter万物皆Widget,所有Widget都有自己的生命周期。常用Widget分StatefulWidget和StatelessWidget,StatelessWidget是无状态组件没有生命周期的概念,StatefulWidget则创建State,有State管理页面生命周期。所以我们只要了解StatefulWidget生命周期就大致知道组件页面生命周期。

StatefulWidget

组件中所包含的所有与生命周期相关的方法如下:

  • createState
  • initState
  • didChangeDependencies
  • build
  • setState
  • deactivate
  • dispose
  • reassemble
  • didUpdateWidget

createState

StatefulWidget组件初始化创建State时调用方法

 @override
  _StatefulLifecycleDemoState createState() {
    print("$TAG  createState");
    return _StatefulLifecycleDemoState();
  }
复制代码

initState

State初始化时的方法,相当于当前Widget创建初始化完毕

build

  • After calling [initState].
  • After calling [didUpdateWidget].
  • After receiving a call to [setState].
  • After a dependency of this [State] object changes (e.g., an [InheritedWidget] referenced by the previous [build] changes).
  • After calling [deactivate] and then reinserting the [State] object into the tree at another location.

当调用initState、didUpdateWidget、deactivate后都会调用build。

setState

当调用setState触发页面数据更新,同时会调用build重新绘制widget树。

setState(() {
});
复制代码

reassemble

绝大多数组件不会调用

在测试环境热更新下会触发

deactivate

当组件的state从树中移除或重新加载到树中时会调用。 可以理解为该组件停用时调用,例如启动新组件页面时和回到该组件页面时都会调用。同时调用deactivate后会调动build

didChangeDependencies

第一次调用是在当组件创建时initState之后。另外若组件依赖了InheritedWidget的数据则会在必要情况下调用。

didUpdateWidget

当父级组件发生变化需要重绘UI则会触发,通过当前组件和oldWidget参数对比做额外逻辑判断。

dispose

当该组件从永久树中彻底移除时调用,类比Android中的onDestory

常见例子

Navigator.of(context).push打开一个StatefulWidget组件时

日志打印如下:

 StatefulLifecycleDemo  createState
 StatefulLifecycleDemo  initState
 StatefulLifecycleDemo  didChangeDependencies
 StatefulLifecycleDemo  build
 StatefulLifecycleDemo  SchedulerBinding
复制代码

StatefulWidget调用setState时

日志打印如下:

 StatefulLifecycleDemo  setState
 StatefulLifecycleDemo  build
复制代码

StatefulWidget调用Navigator.of(context).push打开新页面再返回

日志打印如下:

StatefulLifecycleDemo  deactivate
StatefulLifecycleDemo  build
StatefulLifecycleDemo  deactivate
StatefulLifecycleDemo  build 
//由此可见挂起和重载都会调用deactivate和build
复制代码

关闭当前StatefulWidget

日志打印如下:

StatefulLifecycleDemo  deactivate
StatefulLifecycleDemo  dispose
复制代码

其他

WidgetsBindingObserver

可配置在应用主入口处监听全局应用状态。

  • Future didPopRoute() => Future.value(false);//路由出栈
  • Future didPushRoute(String route) => Future.value(false); //路由入栈
  • void didChangeMetrics() { } //系统窗口发生变化,如屏幕旋转
  • void didChangeTextScaleFactor() { } //系统字体变化
  • void didChangePlatformBrightness() { }//屏幕亮度变化
  • void didChangeLocales(List locale) { }//语言变化
  • didChangeAppLifecycleState(AppLifecycleState state) { } //生命周期变化
  • didHaveMemoryPressure() { }//低内存警告
  • didChangeAccessibilityFeatures() { }//系统活动特性变化

这里我们只关注生命周期相关的didChangeAppLifecycleState,监听应用状态回调。 所有可以监听的状态如下:

  • resumed(处于前台)
  • inactive(挂起,失去焦点)
  • paused(处于后台)
  • suspending(暂停)

代码段

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) {
    super.didChangeAppLifecycleState(state);
    if (state == AppLifecycleState.paused) {
      //页面处于后台
      print("MyHomePage Background");
    }
    if (state == AppLifecycleState.resumed) {
      //页面回到前台
      print("MyHomePage  Foreground");
    }
  }  
}
复制代码

PS:在我使用iOS模拟器的时候下拉状态栏会调用AppLifecycleState.inactive然后App再回到前台会调用AppLifecycleState.resumed并不是调用AppLifecycleState.paused

图解

参考