了解了keepalive的大致过程,在项目中,"我的"页内部是一个由tabbar和pageview联动的widget,选中tab时会在widget中保存一个value表示当前位置,但是,如果不做任何处理,当从"我的"切换到其他页面比如"首页"时,"我的"页的widget将会被移出widget tree和销毁,所以重新切回"我的"页时,选中的tab变回默认,但这不是我们想要的表现。flutter提供了一种当widget从tree中remove后仍然保存相关变量的方式——AutomaticKeepAliveClientMixin。
在state后面加上with AutomaticKeepAliveClientMixin,并重写wantKeepAlive的getter,这样任何情况下这个widget都会被保存。
class _MineTabState extends State<MineTab> with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true;
}
他的实现原理大致如下,AutomaticKeepAliveClientMixin内部有一个_ensureKeepAlive方法,内部会向上发送一个KeepAliveNotification通知,当initState、updateState以及deactivate时都会发送这个通知:
mixin AutomaticKeepAliveClientMixin<T extends StatefulWidget> on State<T> {
KeepAliveHandle _keepAliveHandle;
void _ensureKeepAlive() {
assert(_keepAliveHandle == null);
_keepAliveHandle = KeepAliveHandle();
KeepAliveNotification(_keepAliveHandle).dispatch(context);
}
}
当上级中有一个widget是AutomaticKeepAlive类型时,内部的NotificationListener会接受这种通知,然后通过childe 的 Element去保存该widget,但是从表现上看,假如AutomaticKeepAlive和发送通知的widget中间隔了几层widget的话,中间的几层widget也会跟着发送通知的widget一起被保存下来。
class _AutomaticKeepAliveState extends State<AutomaticKeepAlive> {
void _updateChild() {
_child = NotificationListener<KeepAliveNotification>(
onNotification: _addClient,
child: widget.child,
);
}
再继续往上查看源码,可以看到,pageview内部是有一个AutomaticKeepAlive类型的widget去包裹child的,这可能就是pageview可以快速支持keepalive的原因了,flutter中似乎所有的可滚动widget都默认开启了keepalive,这应该是滚动的一种优化,减少滚动中item的大量重建。
网友评论