Flutter之可滚动组件子项缓存 KeepAlive详解

本文为大家分析了Flutter之可滚动组件子项缓存 KeepAlive,供大家参考,具体内容如下

首先回想一下,在介绍 ListView 时,有一个addAutomaticKeepAlives 属性我们并没有介绍,如果addAutomaticKeepAlives 为 true,则 ListView 会为每一个列表项添加一个 AutomaticKeepAlive 父组件。虽然 PageView 的默认构造函数和 PageView.builder 构造函数中没有该参数,但它们最终都会生成一个 SliverChildDelegate 来负责列表项的按需加载,而在 SliverChildDelegate 中每当列表项构建完成后,SliverChildDelegate 都会为其添加一个 AutomaticKeepAlive 父组件。下面我们就先介绍一下 AutomaticKeepAlive 组件。

AutomaticKeepAlive

AutomaticKeepAlive 的组件的主要作用是将列表项的根 RenderObject 的 keepAlive 按需自动标记 为 true 或 false。为了方便叙述,我们可以认为根 RenderObject 对应的组件就是列表项的根 Widget,代表整个列表项组件,同时我们将列表组件的 Viewport区域 + cacheExtent(预渲染区域)称为加载区域 :

1.当 keepAlive 标记为 false 时,如果列表项滑出加载区域时,列表组件将会被销毁。
2.当 keepAlive 标记为 true 时,当列表项滑出加载区域后,Viewport 会将列表组件缓存起来;当列表项进入加载区域时,Viewport 从先从缓存中查找是否已经缓存,如果有则直接复用,如果没有则重新创建列表项。

那么 AutomaticKeepAlive 什么时候会将列表项的 keepAlive 标记为 true 或 false 呢?答案是开发者说了算!Flutter 中实现了一套类似 C/S 的机制,AutomaticKeepAlive 就类似一个 Server,它的子组件可以是 Client,这样子组件想改变是否需要缓存的状态时就向 AutomaticKeepAlive 发一个通知消息(KeepAliveNotification),AutomaticKeepAlive 收到消息后会去更改 keepAlive 的状态,如果有必要同时做一些资源清理的工作(比如 keepAlive 从 true 变为 false 时,要释放缓存)。

我们基于上一节 PageView 示例,实现页面缓存,根据上面的描述实现思路就很简单了:让Page 页变成一个 AutomaticKeepAlive Client 即可。为了便于开发者实现,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 收到消息后就会开始工作。

现在我们重新运行一下示例,发现每个 Page 页只会 build 一次,缓存成功了。需要注意,如果我们采用 PageView.custom 构建页面时没有给列表项包装 AutomaticKeepAlive 父组件,则上述方案不能正常工作,因为此时Client 发出消息后,找不到 Server,404 了。

KeepAliveWrapper

虽然我们可以通过 AutomaticKeepAliveClientMixin 快速的实现页面缓存功能,但是通过混入的方式实现不是很优雅,因为必须更改 Page 的代码,有侵入性,这就导致不是很灵活,比如一个组件能同时在列表中和列表外使用,为了在列表中缓存它,则我们必须实现两份。为了解决这个问题,笔者封装了一个 KeepAliveWrapper 组件,如果哪个列表项需要缓存,只需要使用 KeepAliveWrapper 包裹一下它即可。

@override
Widget build(BuildContext context) {
  var children = <Widget>[];
  for (int i = 0; i < 6; ++i) {
    //只需要用 KeepAliveWrapper 包装一下即可
    children.add(KeepAliveWrapper(child:Page( text: '$i'));
  }
  return PageView(children: children);
}

下面是 KeepAliveWrapper 的实现源码:

class KeepAliveWrapper extends StatefulWidget {
  const KeepAliveWrapper({
    Key? key,
    this.keepAlive = true,
    required this.child,
  }) : super(key: key);
  final bool keepAlive;
  final Widget child;
 
  @override
  _KeepAliveWrapperState createState() => _KeepAliveWrapperState();
}
 
class _KeepAliveWrapperState extends State<KeepAliveWrapper>
    with AutomaticKeepAliveClientMixin {
  @override
  Widget build(BuildContext context) {
    super.build(context);
    return widget.child;
  }
 
  @override
  void didUpdateWidget(covariant KeepAliveWrapper oldWidget) {
    if(oldWidget.keepAlive != widget.keepAlive) {
      // keepAlive 状态需要更新,实现在 AutomaticKeepAliveClientMixin 中
      updateKeepAlive();
    }
    super.didUpdateWidget(oldWidget);
  }
 
  @override
  bool get wantKeepAlive => widget.keepAlive;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Flutter之可滚动组件子项缓存 KeepAlive详解

    本文为大家分析了Flutter之可滚动组件子项缓存 KeepAlive,供大家参考,具体内容如下 首先回想一下,在介绍 ListView 时,有一个addAutomaticKeepAlives 属性我们并没有介绍,如果addAutomaticKeepAlives 为 true,则 ListView 会为每一个列表项添加一个 AutomaticKeepAlive 父组件.虽然 PageView 的默认构造函数和 PageView.builder 构造函数中没有该参数,但它们最终都会生成一个 Sli

  • Flutter SizedBox布局组件Widget使用示例详解

    目录 正文 child 的 constrains 确定自己的大小 SizedBox 的命名构造函数们 SizedBox.expand SizedBox.shrink SizedBox.fromSize SizedBox.square 应用场景 为 child 提供 tight 约束. 为 children 之间提供空白. 占位 正文 Flutter Sizedbox 是一个 布局组件,用来给 child 添加 tight 约束的,也可以用来添加空白. width,height是 Sizedbox

  • Flutter绘图组件之CustomPaint使用详解

    目录 简介 CustomPaint介绍 CustomPainter示例 总结 简介 在有些场景中,我们会需要绘制一些高度定制化的组件,比如 UI 设计师给我们出了个难题 —— 弄一个奇形怪状的边框.看在 UI 设计师是一个漂亮小姐姐的份上,又不好意思说这个做不了(那样也很没面子).这个时候我们就不能直接使用 Flutter 自带的那些组件了,而是需要手动绘制组件,那就会需要用到 CuntomPaint 组件.CustomPaint 组件和前端的 Canvas差不多,允许我们在一个画布上绘制各种元

  • Android Flutter表格组件Table的使用详解

    目录 Table.TabRow.TabCell 小结 之前开发中用到的表格,本篇文章主要介绍如何在页面中使用表格做一个记录. Table组件不同于其它Flex布局,它是直接继承的RenderObjectWidget的.相当于是一个独立的组件,区别与其他系列组件. Table.TabRow.TabCell 惯例,先看下Table相关的构造方法: Table({ Key? key, this.children = const <TableRow>[],//行列表 表示多少行 this.column

  • vue的生命周期钩子与父子组件的生命周期详解

    目录 vue的生命周期钩子的介绍 父子组件的生命周期 加载渲染过程 父组件更新过程 子组件更新过程 父子组件更新过程 销毁过程 代码示例 created和mounted的区别 vue的生命周期钩子的介绍 vue官网中提供的vue的生命周期钩子图 vue的生命周期可以分为8个阶段: 1.创建vue实例涉及的两个钩子 (1)beforeCreate:创建前,vue实例初始化之前调用. 此时的数据观察和事件配置都还没有准备好,而此时的实例中的data和el还是underfined状态,不可用的.Dom

  • 微信小程序组件之srcoll-view的详解

    微信小程序组件之srcoll-view的详解 今天记录一下scroll-view学习中遇到的问题及解决办法,希望能对其他同学有所帮助. 首先展示一下想达到的效果.↓ vertical scroll实现上下滚动,horizontal实现左右滚动. 先附上wxml的代码. <view class="container"> <view> <text>vertical scroll</text> <scroll-view scroll-y

  • vue 组件高级用法实例详解

    一.递归组件 组件在它的模板内可以递归地调用自己, 只要给组件设置name 的选项就可以了. 示例如下: <div id="app19"> <my-component19 :count="1"></my-component19> </div> Vue.component('my-component19',{ name: 'my-component19', //其实当你利用 Vue.component 全局注册了一个组件

  • vue服务端渲染缓存应用详解

    服务端渲染简介 服务端渲染不是一个新的技术:在 Web 最初的时候,页面就是通过服务端渲染来返回的,用 PHP 来说,通常是使用 Smarty 等模板写模板文件,然后 PHP 服务端框架将数据和模板渲染为页面返回,这样的服务端渲染有个缺点就是一旦要查看新的页面,就需要请求服务端,刷新页面. 但如今的前端,为了追求一些体验上的优化,通常整个渲染在浏览器端使用 JS 来完成,配合 history.pushState 等方式来做单页应用(SPA: Single-Page Application),也收

  • 基于Nginx的Mencached缓存配置详解

    简介 memcached是一套分布式的高速缓存系统,memcached缺乏认证以及安全管制,这代表应该将memcached服务器放置在防火墙后.memcached的API使用三十二比特的循环冗余校验(CRC-32)计算键值后,将数据分散在不同的机器上.当表格满了以后,接下来新增的数据会以LRU机制替换掉.由于memcached通常只是当作缓存系统使用,所以使用memcached的应用程序在写回较慢的系统时(像是后端的数据库)需要额外的代码更新memcached内的数据 特征 memcached作

  • React如何利用Antd的Form组件实现表单功能详解

    一.构造组件 1.表单一定会包含表单域,表单域可以是输入控件,标准表单域,标签,下拉菜单,文本域等. 这里先引用了封装的表单域 <Form.Item /> 2.使用Form.create处理后的表单具有自动收集数据并校验的功能,但如果不需要这个功能,或者默认的行为无法满足业务需求,可以选择不使用Form.create并自行处理数据 经过Form.create()包装过的组件会自带this.props.form属性,this.props.form提供了很多API来处理数据,如getFieldDe

随机推荐