修改GetX Obs监听的类列表内部属性后UI不更新如何解决?
GetX 可观察列表修改元素属性不触发UI更新的解决方案
根本原因
RxList 默认只会监听列表集合本身的变动:包括增删元素、替换元素引用、列表长度变化等。你修改列表内UserMessagesModel实例的单个属性时,列表本身的结构和元素引用没有发生任何变化,因此不会触发Obx的更新通知,第二次操作才生效是因为第二次操作触发了列表层面的变动,顺带渲染了之前修改的属性。
可用解决方案
方法1:主动调用Rx对象的refresh方法(最简单通用)
修改完属性后,直接调用RxList自带的refresh()方法主动触发更新通知,不需要改动其他逻辑:
socket.on("msg_delivered", (del) { OfflineDatabaseManager.instance.updateMsgReadData(del).then((value) { uController.msgChat.forEach((el) { if (el.msgId == del) { print(el.msgId); el.isRead = 'true'; } }); // 新增这一行主动触发列表刷新 uController.msgChat.refresh(); }); });
方法2:替换列表对应索引的元素(无需主动刷新)
找到目标元素的索引后,直接替换列表中该位置的元素,让RxList检测到元素引用变动自动触发更新,如果模型类有copyWith方法更推荐用这种写法:
socket.on("msg_delivered", (del) { OfflineDatabaseManager.instance.updateMsgReadData(del).then((value) { // 用asMap同时获取索引和元素 uController.msgChat.asMap().forEach((index, el) { if (el.msgId == del) { print(el.msgId); // 写法1:修改后重新赋值给对应索引 el.isRead = 'true'; uController.msgChat[index] = el; // 写法2(更推荐,避免引用相同不触发更新):用copyWith生成新实例替换 // uController.msgChat[index] = el.copyWith(isRead: 'true'); } }); }); });
方法3:模型属性也定义为可观察变量(性能最优,局部刷新)
如果需要频繁修改列表元素的单个属性,推荐把模型类中需要变动的属性也定义为Rx类型,修改属性时只会刷新对应Item的UI,不需要刷新整个列表:
- 调整
UserMessagesModel定义:
class UserMessagesModel { final String msgId; // 将需要变动的属性定义为Rx类型 final isRead = 'false'.obs; UserMessagesModel(this.msgId); }
- 列表Item的UI中直接监听属性变化:
Obx(() => Text( el.isRead.value == 'true' ? '已读' : '未读', ))
- 修改属性时不需要操作列表,直接赋值即可自动刷新对应UI:
if (el.msgId == del) { el.isRead.value = 'true'; }
内容的提问来源于stack exchange,提问作者Brightcode
相关产品推荐
相关产品推荐

