Flutter 中 ValueNotifier<List<T>> 监听问题解决
Posted 一叶飘舟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter 中 ValueNotifier<List<T>> 监听问题解决相关的知识,希望对你有一定的参考价值。
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("李四");
这种应用场景如实际项目开发中的修改用户数据,只修改了其中的一个属性数据,可以考虑使用这种方法,当然有很多情况大家是不考虑这种细节的,直接全部更新的,但是所有的细节综合起来,就解决了 你的应用为什么体验总是差点的问题。
以上是关于Flutter 中 ValueNotifier<List<T>> 监听问题解决的主要内容,如果未能解决你的问题,请参考以下文章
Flutter 中 ValueNotifier<List<T>> 监听问题解决
如何在 Flutter 中添加多个相同类型的 ChangeNotifierProvider
Flutter 中 ChangeNotifier 的构建器小部件