【Flutter 问题系列第 77 篇】在 Flutter 中如何使用 ValueNotifier 和 ValueListenableBuilder 实现局部刷新

这是【Flutter 问题系列第 77 篇】,如果觉得有用的话,欢迎关注专栏。

环境:
Flutter SDK:3.3.5、Dart SDK 2.18.2

一:问题描述

Flutter 中刷新 UI 用的 setState 方法, 对于简单的页面可以直接调用这个方法进行刷新页面,但如果页面比较复杂,只是因为一个字符的更改就去刷新整个页面,从性能上来说并不合适。

除了使用状态管理外,Flutter 也提供了局部刷新的组件和 API,比如 StatefulBuilder、StreamBuilder、ValueListenableBuilder、GlobalKey 等方式。

下面说一下如何使用 ValueListenableBuilder 组件做局部刷新。

二:ValueListenableBuilder 结合 ValueNotifier 实现局部刷新

使用 ValueListenableBuilder 组件做局部刷新,需要结合 ValueNotifier 使用。前者负责 UI 的刷新,后者负责数据的更新,并通知 UI 刷新。

比如现在有一个小功能,点击一个按钮,让屏幕上的数字自增。

第一步:

使用 ValueNotifier 注册数据监听器,如下代码所示

final ValueNotifier<int> _counter = ValueNotifier<int>(0);

ValueNotifier 的监听类型是一个泛型,因为我们这里要实现的是监听数字自增,所以定义为了 int 类型,后面小括号内的 0 是当前监听类型的默认值。

然后在 dispose 方法中释放 ValueNotifier 的监听,避免内存泄露。

  @override
  void dispose() {
    
    
    _counter.dispose();
    super.dispose();
  }

第二步:

使用 ValueListenableBuilder 绑定监听,并实现数据更新的方法,如下代码所示

  @override
  Widget build(BuildContext context) {
    
    
    return Scaffold(
      body: Column(
        children: <Widget>[
          ElevatedButton(
            onPressed: () => _counter.value += 1,
            child: Text("点击按钮自增数字"),
          ),
          ValueListenableBuilder<int>(
            valueListenable: _counter,
            builder: (BuildContext context, int value, Widget? child) {
    
    
              return Text(
                '当前数字已自增到了:$value',
                style: Theme.of(context).textTheme.headline4,
              );
            },
          )
        ],
      ),
    );
  }

「更新数据」的方式就是改变 ValueNotifier 的 value 的值。

「绑定监听」就是将我们定义的 ValueNotifier 传给 ValueListenableBuilder 组件的属性 valueListenable。

「获取数据」的方式就是从 ValueListenableBuilder 组件 builder 属性的回调中取 value 值即可。

此时,点击按钮更新数据并刷新 UI 的时候,如果你页面中有其它的组件,value 的刷新并不会影响到其它组件。

至此,就完成了使用 ValueNotifier 和 ValueListenableBuilder 做局部刷新的功能。上面是如何使用,如果你对其源码感兴趣,也可以继续往下看。

三:源码分析

这里先把 ValueNotifierValueListenableBuilder 的官方文档链接贴出来,方便大家看。

这两个组合成的局部刷新这么好用,你或许会觉得它们的源码应该很复杂吧,其实两者的代码如果不算注释的话加起来还没有 50 行。

接下来我们分别看下它们的“庐山真面目”,先来看一下 ValueNotifier 的源码。

1:ValueNotifier

源码如下截图所示

在这里插入图片描述

可以看到,ValueNotifier 继承于 ChangeNotifier 的,并实现了接口 ValueListenable ,监听的类型值是泛型。

get 方法就是获取私有的 _value 值,这个没啥说的。set 方法做了一个判断,如果当前更新后的值和更新前的值相同,则不会触发 UI 刷新,也是一个小优化吧。如果刷新后的值不同,则会调用 notifyListeners 方法通知相应组件刷新 UI。

2:ValueListenableBuilder

源码一

如下截图所示

在这里插入图片描述

可以看到 ValueListenableBuilder 继承于 StatefulWidget 组件,提供了两个必传属性 valueListenable、builder 和一个选传属性 child。

其中 valueListenable 的类型为 ValueListenable,所以 ValueNotifier 可以当作入参传入。

builder 属性的实现代码如下所示

typedef ValueWidgetBuilder<T> = Widget Function(BuildContext context, T value, Widget? child);

一般我们只是通过 builder 属性拿到 value 值做展示使用。

源码二

接下来我们看下核心部分 _ValueListenableBuilderState 的源码实现,如下图所示

在这里插入图片描述

ValueListenableBuilder 局部刷新如何实现的 ?

可以看到,在 initState 方法中对传入的数据进行监听,而 _valueChanged 方法对数据进行了更新,并调用了 setState 方法(刷新的本质)触发了其 build 方法,然后进入了 widget.builder 的回调,这样就实现了局部刷新。

而 build 方法中回调的 child,也是组件传入的 child,这也是对 child 优化的根源,这种实现方式在其它组件中也会经常见到。

ValueListenableBuilder 局部刷新的本质

其实就是对组件进行了抽离,让组件状态的改变只在其内部进行更改,然后通过 builder 属性回调控制局部刷新,并暴露给开发者使用。

至此,关于在 Flutter 中使用 ValueNotifier 和 ValueListenableBuilder 实现局部刷新,便介绍到这里。

你的问题得到解决了吗?欢迎在评论区留言。

赠人玫瑰,手有余香,如果觉得文章不错,希望可以给个一键三连,感谢。


结束语

Google 的 Flutter 越来越火,截止 2023年5月3日 GitHub 标星已达 153K,Flutter 毅然是一种趋势,所以作为前端开发者,没有理由不趁早去学习。

无论你是 Flutter 新手还是已经入门了,不妨先点个关注,后续我会将 Flutter 中的常用组件(含有源码分析、组件的用法及注意事项)以及可能遇到的问题写到 CSDN 博客中,希望自己学习的同时,也可以帮助更多的人。

猜你喜欢

转载自blog.csdn.net/qq_42351033/article/details/130474748