iOS-Flutter State及APP生命周期

123 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 4 天,点击查看活动详情

1、State 生命周期

先引用一张图 image.png 再看源码

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

image.png

3、帧绘制回调

在组件完成渲染后做的一些和显示相关的其他处理,比如现场切换,可以使用WidgetsBinding来实现。 WidgetsBinding提供了单词Frame绘制回调和实时 Frame绘制回调两种机制.

  • 单词Frame绘制回调,通过addPistFrameCallback实现。在当前Frame绘制完成后进行回调,且只会回调一次,如果需要多次回调则手动设置。
WidgetsBindingObserver.instance.addPostFrameCallback((_){
  print("addPostFrameCallback 绘制回调"); // 只回调一次
});
  • 实时Frame绘制回调;通过addPersistertFrameCallback实现。在每次绘制Frame结束后,进行回调.
WidgetsBindingObserver.instance.addPersistentFrameCallback((_){
  print("addPersistentFrameCallback 绘制回调"); // 每帧都回调
});