当前位置:网站首页>Flutter 中 ValueNotifier<List<T>> 监听问题解决
Flutter 中 ValueNotifier<List<T>> 监听问题解决
2022-06-26 21:38:00 【一叶飘舟】
1. 起因
开发中遇到一个问题 ValueNotifier<List<T>> 监听失败, 初步确认原因是数组值发生改变但是地址未发生改变,与 iOS 监听数组需要特别处理一样;需要二次赋值触发地址改变,触发监听机制;
2.结果:完美解决问题
最终简单封装如下:
/// 泛型数组监听
class ValueNotifierList<T> extends ValueNotifier<List<T>> {
ValueNotifierList(List<T> initValue) : super(initValue);
void add(T item) {
value.add(item);
_copyValue();
}
/// 删除
void remove(int index) {
if (value.length < index) {
return;
}
value.removeAt(index);
_copyValue();
}
/// 删除最后
void removeLast() {
if (value.length == 0) {
return;
}
value.removeLast();
_copyValue();
}
void removeAll() {
value.clear();
_copyValue();
}
/// 利用深copy 重新赋值,触发监听
void _copyValue() {
value = [...value];
}
@override
String toString() {
return "${this.runtimeType} 共 ${value.length} 件商品}";
}
}
3. example:
/// ValueNotifier
static ValueNotifierList valueNotifierList = ValueNotifierList(<OrderModel>[]);
/// ValueNotifier(addListener无效 因为数组地址未发生改变, 推荐使用 ValueNotifierList)
static ValueNotifier<List<OrderModel>> valueNotifierListOrigin = ValueNotifier(<OrderModel>[]);
...
@override
void initState() {
super.initState();
valueNotifierList.addListener(update);
valueNotifierListOrigin.addListener(update);
}
@override
void dispose() {
valueNotifierList.removeListener(update);
valueNotifierListOrigin.removeListener(update);
super.dispose();
}
...
void update() {
showSnackBar(SnackBar(content: Text("数据变化监听回调, 刷新重建界面",)), true);
setState(() {});
}
...
void handleActionNum({required ValueNotifierModel e, required int value, required int idx}) {
switch (e.name) {
case "valueNotifierList":
{
final e = OrderModel(name: '商品', id: 99, pirce: 1.00);
if (value > 0) {
valueNotifierList.add(e);
} else {
valueNotifierList.removeLast();
}
ddlog(valueNotifierList.toString());
// ddlog("${cartModelOneKey.totalPrice}");
}
break;
case "valueNotifierListOrigin":
{
final e = OrderModel(name: '商品', id: 99, pirce: 1.00);
if (value > 0) {
valueNotifierListOrigin.value.add(e);
} else {
valueNotifierListOrigin.value.removeLast();
}
update();///监听无效,需要手动调整
ddlog(valueNotifierListOrigin.value.length.toString());
// ddlog("${cartModelOneKey.totalPrice}");
}
break;
default:
break;
}
}
延伸:Flutter ValueNotifier 异步通信、ValueListenableBuilder异步更新数据
在 Flutter 中可用于异步通信的方案有如下:
- Provider
- ValueNotifier
- Stream
- EventBus (不考虑使用)
- Bloc BLoC
本文章讲述使用 Navigator 更新页面 A 的数据、ValueListenableBuilder 的基本使用、自定义 ValueNotifier 进行局部数据的更新
1 前言
在实际项目开发中,有一种业务需求就是 页面A 进入页面B ,在页面B中数据发生改变后需要更新页面A 中的内容,其实第一种方案可以考虑使用 then函数回调,如下代码清单1-1所示,在页面A中以动态路由的方式打开页面TestBPage,并实现 Navigator 的then 函数,then 函数会在 TestBPage 页面关闭时回调。
///代码清单 1-1
void openPageFunction(BuildContext context) {
///以动态路由的方式打开
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return TestBPage();
},
),
///页面 TestBPage 关闭后会回调 then 函数
///其中参数 value 为回传的参数
).then((value) {
if (value != null) {
setState(() {
_message = value;
});
}
});
}
当在页面 TestBPage 关闭时,可以主动回传参数,如下代码 清单 1-2 所示:
///代码 清单 1-2
OutlineButton buildOutlineButton(BuildContext context) {
return OutlineButton(
child: Text("返回页面 A "),
onPressed: () {
String result = "345";
Navigator.of(context).pop(result);
},
);
}
这一种方法的一个实际应用场所如一个订单的详情页面,打开下一个页面进行操作后,再返回当前页面后需要刷新页面的数据,此种场景就可使用这种方法。
使用 then 函数达成的数据传递或者说页面刷新,对于用户来讲是可见的,就是有时数据刷新的慢点,用户是可以有感觉的,使用ValueNotifier可以达到无感刷新。
2 ValueNotifier 的基本使用
ValueNotifier 需要结合组件 ValueListenableBuilder 来使用。
/// 第一步 定义 ValueNotifier 这里传递的数据类型为 String
ValueNotifier<String> _testValueNotifier = ValueNotifier<String>('');
///第二步定义 数据变化后监听的 Widget
Widget buildValueListenableBuilder() {
return ValueListenableBuilder(
///数据发生变化时回调
builder: (context, value, child) {
return Text(value);
},
///监听的数据
valueListenable: _testValueNotifier,
child: Text(
'未登录',
style: TextStyle(color: Colors.red),
),
);
}
///第三步就是数据变化后
void testFunction() {
///赋值更新
_testValueNotifier.value = '传递的测试数据';
}
在上述代码片段中,传递更新的数据是一个String,当然在业务开发场景中,会有更多自定义的 Model,直接替换上述的String就可以。
3 自定义 ValueNotifier 局部更新
如有一个用户数据类型的Model定义如下 :
///实际中变量可能足够的多
class UserInfo {
String name;
int age ;
}
我们期望只修改其中的如 age 一个属性的值,此时就需要自定 ValueNotifier ,如下代码清单 1-3 所示:
///代码清单 1-3
///自定义 ValueNotifier
/// UserInfo 为数据类型
class UserNotifier extends ValueNotifier<UserInfo> {
UserNotifier(UserInfo userInfo): super(userInfo);
void setName(String name) {
///赋值 这里需要注意的是 如果没有给 ValueNotifier 赋值 UserInfo 对象时
/// value 会出现空指针异常
value.name =name;
///通知更新
notifyListeners();
}
}
然后在使用的时候,创建 UserNotifier 如下 :
///第一步
UserNotifier _testUserNotifier = UserNotifier(UserInfo(name: "", age: 0));
构建 ValueListenableBuilder
///第二步 定义
Widget buildUserListenableBuilder() {
return ValueListenableBuilder(
///数据发生变化时回调
builder: (context, value, child) {
return Text("姓名是:${value.name} 年龄是: ${value.age}");
},
///监听的数据
valueListenable: _testUserNotifier,
);
}
当数据变化时进行更新操作
void testUserFunction() {
_testUserNotifier.setName("李四");
}
这种应用场景如实际项目开发中的修改用户数据,只修改了其中的一个属性数据,可以考虑使用这种方法,当然有很多情况大家是不考虑这种细节的,直接全部更新的,但是所有的细节综合起来,就解决了 你的应用为什么体验总是差点的问题。
边栏推荐
- 记录一次Redis大Key的排查
- Shiniman household sprint A shares: annual revenue of nearly 1.2 billion red star Macalline and incredibly home are shareholders
- Background search, how to find the website background
- Can compass open an account for stock trading? Is it safe?
- 360手机助手首家接入APP签名服务系统 助力隐私安全分发
- 【 protobuf 】 quelques puits causés par la mise à niveau de protobuf
- y48.第三章 Kubernetes从入门到精通 -- Pod的状态和探针(二一)
- Installation avec homebrew dans un environnement Mac OS [email protected]
- 经典Wide & Deep模型介绍及tensorflow 2代码实现
- 网络连接断开请刷新重试
猜你喜欢
【 protobuf 】 quelques puits causés par la mise à niveau de protobuf
茂莱光学科创板上市:拟募资4亿 范一与范浩兄弟为实控人
Configure redis master-slave and sentinel sentinel in the centos7 environment (solve the problem that the sentinel does not switch when the master hangs up in the ECS)
Hands on deep learning pytorch version 3 - Data Preprocessing
2022年,中轻度游戏出海路在何方?
诗尼曼家居冲刺A股:年营收近12亿 红星美凯龙与居然之家是股东
QT based "synthetic watermelon" game
What are the accounting elements
Icml2022 | neurotoxin: a lasting back door to federal learning
Vi/vim editor
随机推荐
矩阵求导及其链式法则
诗尼曼家居冲刺A股:年营收近12亿 红星美凯龙与居然之家是股东
大家都能看得懂的源码(一)ahooks 整体架构篇
QT环境下配置Assimp库(MinGW编译器)
leetcode刷题:哈希表08 (四数之和)
YuMinHong: New Oriental does not have a reversal of falling and turning over, destroying and rising again
网络爬虫2:抓取网易云音乐评论用户ID及主页地址
基于Qt实现的“合成大西瓜”小游戏
Leetcode: hash table 08 (sum of four numbers)
在哪家证券公司开户最方便最安全可靠
Sword finger offer II 098 Number of paths / Sword finger offer II 099 Sum of minimum paths
Redis + Guava 本地缓存 API 组合,性能炸裂!
Can compass open an account for stock trading? Is it safe?
Godson China Science and technology innovation board is listed: the market value is 35.7 billion yuan, becoming the first share of domestic CPU
Leetcode(122)——买卖股票的最佳时机 II
How to create an OData service with the graphical modeler on the sap BTP platform
Android mediacodec hard coded H264 file (four), ByteDance Android interview
DAST 黑盒漏洞扫描器 第五篇:漏洞扫描引擎与服务能力
传纸条【动态规划】
基于SSH框架的学生信息管理系统