我的解决办法
- 在报错的类中的创建一个 静态方法变量
- 构造方法赋值给 静态变量 当前的notifyListeners方法
- 通知时每次调用 静态变量 而非 自己 的notifyListeners
简单demo
class Cart extends ChangeNotifier {
// 1.在报错的类中的创建一个 静态方法变量
static Function staticNotifyListeners;
static bool onceExe = true;
Cart(int num, Cart oldCart) {
// 2.构造方法赋值给 静态变量 当前的notifyListeners方法
staticNotifyListeners=notifyListeners;
debugPrint("cartInit:__"+hashCode.toString());
if(onceExe){
testLazyNotifier();
onceExe=false;
}
}
void testLazyNotifier() async {
await Future.delayed(Duration(seconds: 5), () {
debugPrint("future end :"+hashCode.toString());
finalNum = 998;
// 3.通知时每次调用 静态变量 而非 自己 的notifyListeners
staticNotifyListeners();
});
}
int finalNum;
}
解刨问题
我出现该问题的场景:
- 使用了 provider 中的 ChangeNotifierProxyProvider
- ChangeNotifierProxyProvider 中的异步方法 调用了 notifyListeners
思考报错信息
E/flutter (19338): [ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: A Cart was used after being disposed.
E/flutter (19338): Once you have called dispose() on a Cart, it can no longer be used.
使用了已经disposed 的方法.
一开始我想不明白,这究竟是什么意思.
我做了个实验.
分别在三个地方 输出 问题对象 的id,参考文章最上面的代码
- 问题对象构造函数
- 调用notifyListeners 的前一刻
- 使用 该对象 位置
重现问题并输出结果
I/flutter (19338): cartInit:__876590056
I/flutter (19338): buildCart:__876590056
I/flutter (19338): cartInit:__38033970
I/flutter (19338): buildCart:__38033970
I/flutter (19338): future end :876590056
E/flutter (19338): [ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: A Cart was used after being disposed.
E/flutter (19338): Once you have called dispose() on a Cart, it can no longer be used.
思考问题产生
I/flutter (19338): cartInit:__876590056
I/flutter (19338): buildCart:__876590056
创建了 876590056 对象, 并在 build 中使用
I/flutter (19338): cartInit:__38033970
I/flutter (19338): buildCart:__38033970
由于依赖的父亲发生了变化,导致 子节点更新.
更新重建依赖对象为 38033970
I/flutter (19338): future end :876590056
因为 异步方法 是在 876590056 中执行的,他所调用的 notifyListeners 是 废弃对象 中的,所以报错.
总结
异步方法是在旧对象中执行 等他执行完毕后 notifyListeners 方法通知的是 旧对象
旧的对象在被替换时会被调用
class ChangeNotifier 中的 如下方法
@mustCallSuper
void dispose() {
assert(_debugAssertNotDisposed());
_listeners = null;
}
被 dispose 的对象 冥顽不顾 接着调用 notifyListeners 导致 意外发生
bool _debugAssertNotDisposed() {
assert(() {
if (_listeners == null) {
throw FlutterError(
'A $runtimeType was used after being disposed.\n'
'Once you have called dispose() on a $runtimeType, it can no longer be used.'
);
}
return true;
}());
return true;
}