Flutter的生命周期(交互) 当前Frame绘制完后进行回调(addPostFrameCallback)

来源:juejin.cn 时间:2021-03-24 15:11

1. 组件渲染

前面部分,已经介绍过了,组件的构建渲染=> 传送门

2. 前后台交互

在我们原生Android(或者IOS)开发中,很多是否要在对应的生命周期做一些事件,例如App从后台进入前台,从前台退入后台(或被遮盖),以及需要在确保UI绘制后做一些处理,这在我们原生开发中很容易做到,那么在Flutter中需要怎么去做呢?

很简单,给WidgetsBinding设置Observer

class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver{

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);//添加观察者
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    print("lifeChanged $state");
  }

  @override
  void dispose() {
    super.dispose();
    WidgetsBinding.instance.removeObserver(this);//销毁
  }
  
  @override
  Widget build(BuildContext context) {
    return Container();
  }
}
复制代码

通过以上代码,我们可以看到只要给WidgetsBinding的单例对象添加WidgetsBindingObserver,然后此类粘合(with)WidgetsBindingObserver抽象类,在初始化State的时候给WidgetsBinding设置Observer为当前类,并在销毁的时候移除Observer,此时我们的State就具备WidgetsBindingObserver的回调了。

(关于with的作用读者可自行搜索相关关键字mixinwith)。

我们看看WidgetsBindingObserver中具体有哪些回调:

abstract class WidgetsBindingObserver {

   //路由弹出Future
  Future<bool> didPopRoute() => Future<bool>.value(false);

    //新的路由Future
  Future<bool> didPushRoute(String route) => Future<bool>.value(false);

    //系统窗口相关改变回调,例如旋转
  void didChangeMetrics() { }

    //文字系数变化
  void didChangeTextScaleFactor() { }

    //本地化语言变化
  void didChangeLocales(List<Locale> locale) { }

    //生命周期变化
  void didChangeAppLifecycleState(AppLifecycleState state) { }

    //低内存回调
  void didHaveMemoryPressure() { }

    //当前系统改变了一些访问性活动的回调
  void didChangeAccessibilityFeatures() {}
}
复制代码

可以看到,常见的屏幕、字体、语言等变化都会通过此类实现进行回调,这里我们关注生命周期的变化方法didChangeAppLifecycleState

生命周期回调(didChangeAppLifecycleState)

void didChangeAppLifecycleState(AppLifecycleState state) { }

这个方法有一个参数类型为AppLifecycleState的枚举类,我们可以根据它的状态来处理我们的一些任务

enum AppLifecycleState {
  resumed,
  inactive,
  paused,
  suspending,
}
复制代码
  • resumed:应用可见并可响应用户操作
  • inactive:用户可见,但不可响应用户操作
  • paused:已经暂停了,用户不可见、不可操作
  • suspending:应用被挂起,此状态IOS永远不会回调

Flutter回调的生命周期与Android基本上差不多,这里说一下回调比较特别的地方。

以Android为例,当我们Activity创建的时候,流程是这样的:

创建期:onCreate -> onStart -> onResume

进入后台: onPause -> onStop

从后台恢复:onRestart->onResume

而在Flutter中这整个流程是:

创建期: initState

进入后台: inactive -> paused

从后台恢复: inactive -> resumed

对比发现,在我们页面创建的时候不会触发生命周期回调(didChangeAppLifecycleState),而在进入后台和从后台恢复的时候都会先调用inactive(可见,不可响应)然后调用paused(彻底不可见)或者resumed(可见并可操作)。至于挂起(suspending)的回调,笔者暂时还不知道怎样才会触发。

Tips:当生命周期可交互时(resumed)才开始绘制Frame,生命周期变为不可交互时(paused、suspending)会停止绘制Frame,这个后面分析Flutter启动时会介绍。

3. 其它回调

有的时候我们需要在Widget渲染之后做一些安全的操作,在Android中可以通过View.post()插入消息队列,这样可以保证在组件渲染后进行操作,那么Flutter中有没有这样的API呢?当然有啦..

还是我们的WidgetsBinding

3.1 单次Frame绘制回调(addPostFrameCallback)
void initState() {
  super.initState();
  WidgetsBinding.instance.addPostFrameCallback((_){
    print("Frame has been rendered");
  });
}
复制代码

通过addPostFrameCallback可以做一些安全的操作,在有些时候是很有用的,它会在当前Frame绘制完后进行回调,并只会回调一次,如果要再次监听需要再设置。

3.2 实时Frame绘制回调(addPersistentFrameCallback)
WidgetsBinding.instance.addPersistentFrameCallback((_){
  print("Frame has been rendered");
});
复制代码

这个api在每次绘制Frame结束后都会回调,我们可以利用它做一些帧率检测。

这些都是比较常用的,更多有用好玩的api得大家自己去发现。


 
上一篇:Matrix4矩阵变换 下一篇:flutter 事件穿透