Flutter-APP和Widget生命周期详解

2,189 阅读4分钟

Flutter 跟 iOS 的 ViewController、Android 的 Activity 一样拥有自己的生命周期, Flutter中一切都是 Widget,Widget 组件也有自己的生命周期。

生命周期流程图

未命名文件.png

页面的生命周期

在应用中有时候需要判断应用的前后台状态,比如播放视频、埋点统计等等,Flutter 可以通过WidgetsBindingObserver进行状态的判断。WidgetsBindingObserver 要写在被 MaterialApp 或者其他主题包裹的地方。

AppLifecycleState 对应状态说明

  1. inactive 应用程序处于非激活状态,无法响应用户输入
  2. pause 应用程序不可见,而且无法响应用户输入,运行在后台
  3. resumed 应用程序可见并能响应用户输入

生命周期是这样的

  1. 刚进入Widget,不会调用 AppLifecycleState
  2. 从前台切换到后台,调用顺序 AppLifecycleState inactive -> AppLifecycleState pause
  3. 从后台切换到前台,调用顺序 AppLifecycleState inactive -> ApplifecycleState resumed
  4. 从页面返回,会调用 dispose

实现代码,可以这样进行检测

class _AppLifecycleState extends State<AppLifecycle> with WidgetsBindingObserver {

  void dispose() {
    super.dispose();
    print('页面销毁');
    WidgetsBinding.instance?.removeObserver(this);
  }

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance?.addObserver(this);
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    switch (state) {
      case AppLifecycleState.inactive:
        //应用程序处于闲置状态并且没有收到用户的输入事件。
        //注意这个状态,在切换到后台时候会触发,所以流程应该是先冻结窗口,然后停止UI
        print('AppLifecycleState.inactive');
        break;
      case AppLifecycleState.paused:
        //应用程序处于不可见状态
        print('AppLifecycleState.paused');
        break;
      case AppLifecycleState.resumed:
        //进入页面的时候不会触发该状态
        //应用程序处于可见状态,并且可以响应用户的输入事件
        print('YMAppLifecycleState.resumed');
        break;
      case AppLifecycleState.detached:
        //从当前页面离开
        print('AppLifecycleState.detached');
        break;
    }
  }

其他一些状态的回调

  • 底内存发生的回调,原生也有这个方法
@override
void didHaveMemoryPressure() {
  super.didHaveMemoryPressure();
  print('低内存发生的回调');
}
  • 应用尺寸发生改变的回调
@override
void didChangeMetrics() {
  super.didChangeMetrics();
  print('应用尺寸改变时回调');
}
  • 页面 pop 出去的回调
@override
Future<bool> didPopRoute() {
  print('页面pop出去的回调')
  return super.didPopRoute();
}
  • 页面 push 的回调
@override
Future<bool> didPushRoute(String route) {
  print('页面push的回调');
  return super.didPushRoute(route);
}
  • 切换主题的回调
@override
void didChangePlatformBrightness() {
  super.didChangePlatformBrightness();
  print('切换主题的回调');
}

Widget组件的生命周期

在Flutter里面万物皆组件,而组件又分为无状态的组件StatelessWidget,和有状态的组件StatefulWidget,StatefulWidget 组件则可以直接改变当前组件的状态而无需重新创建新的实例,而StatelessWidget 就需要创建新的实例。

更个状态的解析

1. createState

createState 是 StatefulWidget 里创建 State 的方法。当要创建新的StatefulWidget的时候,就会立即执行createState。

2. initState

在 StatefulWidget 第一次创建的时候,initState 是 StatefulWidget 创建完后调用的第一个方法,而且只执行一次,类似于 IOS 的 viewDidLoad()、Android 的 onCreate,所以在这里 View 并没有渲染,但是这时 StatefulWidget 已经被加载到渲染树里了,这时 StatefulWidget 的 mount 的值会变为 true,直到 dispose 调用的时候才会变为 false。一些初始化的工作我们都会选择在这里处理。

3. didChangeDependencies

在 StatefulWidget 第一次创建的时候,didChangeDependencies 方法会在 initState 方法之后立即调用,之后当 StatefulWidget 刷新的时候,就不会调用了,除非你的 StatefulWidget 依赖的 InheritedWidget 发生变化之后,didChangeDependencies 才会调用,所以 didChangeDependencies 有可能会被调用多次。

4. build

在 StatefulWidget 第一次创建的时候,build 方法会在 didChangeDependencies 方法之后立即调用,另外一种会调用 build 方法的场景是,每当 UI 需要重新渲染的时候,build 都会被调用,所以 build 会被多次调用,然后返回要渲染的 Widget。

5. didUpdateWidget

didUpdateWidget 这个生命周期我们一般不会用到,只有在使用 key 对 Widget 进行复用的时候才会调用。

6. deactivate

当要将 State 对象从渲染树中移除的时候,就会调用 deactivate 生命周期,这标志着 StatefulWidget 将要销毁,但是有时候 State 不会被销毁,而是重新插入到渲染树种。

7. dispose

当 View 不需要再显示,从渲染树中移除的时候,State 就会永久的从渲染树中移除,就会调用 dispose 生命周期,这时候就可以在 dispose 里做一些取消监听、动画的操作,和 initState 是相反的。

StatelessWidget的生命周期

  1. 构造方法
  2. build方法

StatefulWidget的生命周期

  1. Widget构造方法
  2. Widget的CreateState
  3. State的构造方法
  4. State的initState方法
  5. didChangeDependencies方法(改变依赖关系),依赖的InheritedWidget发生变化之后,方法也会调用
  6. State的build 当调用setState方法,会重新调用build进行渲染
  7. 当Widget销毁的时候,调用State的dispose

实现代码,可以这样进行检测

class StatefulLifeDemo extends StatefulWidget {
  const StatefulLifeDemo({Key? key}) : super(key: key);

  @override
  _StatefulLifeDemoState createState(){
    print('createState');
    return _StatefulLifeDemoState();
  }
}

class _StatefulLifeDemoState extends State<StatefulLifeDemo> {

  @override
  void initState() {
    super.initState();
    print('initState');
  }

  @override
  void dispose() {
    super.dispose();
    print('dispose');
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    print('didChangeDependencies');
  }

  @override
  void didUpdateWidget(covariant StatefulLifeDemo oldWidget) {
    super.didUpdateWidget(oldWidget);
    print('didUpdateWidget');
  }

  @override
  void setState(VoidCallback fn) {
    super.setState(fn);
    print('setState');
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text('111'),
    );
  }
}