在介绍 ListView 时,有一个addAutomaticKeepAlives
属性并没有介绍,如果addAutomaticKeepAlives
为 true
,则 ListView 会为每一个列表项添加一个 AutomaticKeepAlive 父组件。
虽然 PageView 的默认构造函数和 PageView.builder 构造函数中没有该参数,但它们最终都会生成一个 SliverChildDelegate 来负责列表项的按需加载,而在 SliverChildDelegate 中每当列表项构建完成后,SliverChildDelegate 都会为其添加一个 AutomaticKeepAlive 父组件。
1 AutomaticKeepAlive
AutomaticKeepAlive 的组件的主要作用是将列表项的根 RenderObject 的 keepAlive 按需自动标记 为 true 或 false。为了方便叙述,可以认为根 RenderObject 对应的组件就是列表项的根 Widget,代表整个列表项组件,同时将列表组件的 Viewport区域 + cacheExtent(预渲染区域)称为加载区域:
-
当 keepAlive 标记为 false 时,如果列表项滑出加载区域时,列表组件将会被销毁。
-
当 keepAlive 标记为 true 时,当列表项滑出加载区域后,Viewport 会将列表组件缓存起来;当列表项进入加载区域时,Viewport 从先从缓存中查找是否已经缓存,如果有则直接复用,如果没有则重新创建列表项。
AutomaticKeepAlive 什么时候会将列表项的 keepAlive 标记为 true 或 false 呢?
答案是开发者说了算!
Flutter 中实现了一套类似 C/S 的机制,AutomaticKeepAlive 就类似一个 Server,它的子组件可以是 Client,这样子组件想改变是否需要缓存的状态时就向 AutomaticKeepAlive 发一个通知消息(KeepAliveNotification), AutomaticKeepAlive 收到消息后会去更改 keepAlive 的状态,如果有必要同时做一些资源清理的工作(比如 keepAlive 从 true 变为 false 时,要释放缓存)
Flutter 提供了一个 AutomaticKeepAliveClientMixin 只需要让 PageState 混入这个 mixin,且同时添加一些必要操作即可:
class _PageState extends State<Page> with AutomaticKeepAliveClientMixin {
@override
Widget build(BuildContext context) {
super.build(context); // 必须调用
return Center(child: Text("${widget.text}", textScaleFactor: 5));
}
@override
bool get wantKeepAlive => true; // 是否需要缓存
}
只需要提供一个 wantKeepAlive
,它会表示 AutomaticKeepAlive 是否需要缓存当前列表项;另外我们必须在 build 方法中调用一下 super.build(context)
,该方法实现在 AutomaticKeepAliveClientMixin 中,功能就是根据当前 wantKeepAlive
的值给 AutomaticKeepAlive 发送消息,AutomaticKeepAlive 收到消息后就会开始工作