Flutter中如何用Provider监听ViewModel内对象属性的变化?
问题描述
我有如下ViewModel类:
class Foo extends ChangeNotifier{ // 要修改的对象变量 Object _fooObject = Object(); // 对象的Getter和Setter Object get fooObject => _fooObject; set fooObject(Object value) { _fooObject = value; notifyListeners(); } }
同时有如下自定义Object类:
class Object{ int? property1; String? property2; Object(this.property1,this.property2); }
目前给fooObject赋值新的Object实例时,因为setter里调用了notifyListeners(),UI能正常同步变化。但如果直接修改fooObject的单个属性,比如执行:
Provider.of<Foo>(context).fooObject.property1 = 2;
这种情况下无法触发UI更新,想请教:
- 怎么实时检测这类属性变化?
- 是否需要给每个属性单独写getter和setter?
- 调用
notifyListeners()检测单个属性变化的最佳方案是什么?
方案1:让自定义对象类支持监听
把你的Object类改成继承ChangeNotifier,给每个属性加带通知的setter,然后在Foo里监听这个对象的变化并转发通知:
// 注意别用Object当类名,和dart核心类冲突,改成MyObject class MyObject extends ChangeNotifier { int? _property1; String? _property2; MyObject(this._property1, this._property2); int? get property1 => _property1; set property1(int? value) { if (_property1 != value) { _property1 = value; notifyListeners(); } } String? get property2 => _property2; set property2(String? value) { if (_property2 != value) { _property2 = value; notifyListeners(); } } }
然后修改Foo类,处理对象的监听逻辑:
class Foo extends ChangeNotifier{ late MyObject _fooObject; MyObject get fooObject => _fooObject; set fooObject(MyObject value) { // 先移除旧对象的监听,避免内存泄漏 _fooObject.removeListener(_forwardNotify); _fooObject = value; // 给新对象加监听 _fooObject.addListener(_forwardNotify); notifyListeners(); } Foo() { _fooObject = MyObject(null, null); _fooObject.addListener(_forwardNotify); } void _forwardNotify() { // 把对象属性变化的通知转发给UI notifyListeners(); } @override void dispose() { _fooObject.removeListener(_forwardNotify); super.dispose(); } }
这样修改property1时,MyObject会触发通知,Foo再转发给UI,就能实时更新了。
方案2:在Foo中封装属性修改方法
如果不想改原Object类,可以直接在Foo里给每个属性写修改方法,每次修改都触发notifyListeners():
class Foo extends ChangeNotifier{ Object _fooObject = Object(null, null); Object get fooObject => _fooObject; set fooObject(Object value) { _fooObject = value; notifyListeners(); } // 修改property1的方法 void updateProperty1(int? value) { if (_fooObject.property1 != value) { _fooObject.property1 = value; notifyListeners(); } } // 修改property2的方法 void updateProperty2(String? value) { if (_fooObject.property2 != value) { _fooObject.property2 = value; notifyListeners(); } } }
使用时直接调用这些方法就行:
Provider.of<Foo>(context).updateProperty1(2);
方案3:用不可变对象(推荐)
把Object改成不可变类,所有属性设为final,修改属性时必须创建新实例,这样就能通过Foo的setter触发更新:
class MyObject { final int? property1; final String? property2; const MyObject(this.property1, this.property2); // 提供copyWith方法,快速创建修改后的新实例 MyObject copyWith({int? property1, String? property2}) { return MyObject( property1 ?? this.property1, property2 ?? this.property2, ); } }
修改属性时创建新实例赋值:
final foo = Provider.of<Foo>(context); foo.fooObject = foo.fooObject.copyWith(property1: 2);
这种方式状态更可控,避免意外的隐性修改,也是Flutter生态(比如Bloc、Riverpod)推荐的做法。
方案对比
- 方案1适合频繁修改单个属性、不想每次创建新实例的场景,但要注意维护监听关系,避免内存泄漏。
- 方案2实现最简单,不用改原对象,但属性多的话会有大量重复代码。
- 方案3是复杂应用的最优解,状态更安全,减少潜在bug。
内容的提问来源于stack exchange,提问作者Junaid Tariq
相关产品推荐
相关产品推荐

