Flutter的生命周期(交互) 当前Frame(帧率)绘制完后进行回调(addPostFrameCallback)
更详细可以查看此链接 listview - setState() or markNeedsBuild called during build - Stack Overflow
他有点像vue的 this.$nextTick https://cn.vuejs.org/api/general.html#nexttick
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的作用读者可自行搜索相关关键字mixin、with)。
我们看看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得大家自己去发现。
更新时间:2024-12-18 20:26