You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何合理销毁ChangeNotifierProvider?解决ViewModel释放后调用异常

解决方案

核心问题是页面销毁后,ViewModel的dispose方法已执行,但之前启动的延迟异步任务仍在运行,最终调用notifyListeners()时触发断言错误。解决思路是在ViewModel销毁时取消所有未完成的异步任务,并在更新状态前检查自身活跃状态。

1. 给ViewModel添加异步任务管理能力

使用CancelableOperation(需导入package:async/async.dart)或Timer管理异步任务,并重写dispose方法取消任务:

class ViewModel with ChangeNotifier {
 ApiResponse<String> _apiResponse = ApiResponse.initial("initial");
 CancelableOperation? _cancelableOp; // 管理异步任务

 ApiResponse<String> get apiResponse => _apiResponse;

 set apiResponse(ApiResponse<String> value) {
   // 更新状态前先检查是否已被释放
   if (!mounted) return;
   _apiResponse = value;
   notifyListeners();
 }

 Future<void> fonksiyon() async {
   // 先取消之前的任务,避免重复执行
   _cancelableOp?.cancel();
   _cancelableOp = CancelableOperation.fromFuture(
     Future.delayed(
       const Duration(seconds: 5),
       () {
         apiResponse = ApiResponse.completed("Tamamlandı");
       },
     ),
   );
   await _cancelableOp?.value;
 }

 @override
 void dispose() {
   _cancelableOp?.cancel(); // 销毁时取消所有未完成的任务
   super.dispose();
 }
}

2. 利用mounted状态检查

ChangeNotifier自带mounted属性,在调用notifyListeners()前检查实例是否活跃,避免在已释放对象上执行操作。

3. 优化页面的Provider使用

在SonrakiSayfa中使用Consumer更安全地监听变化,调用方法时用listen: false避免不必要的监听:

class SonrakiSayfa extends StatelessWidget {
 const SonrakiSayfa({Key? key}) : super(key: key);

 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(
       actions: [
         IconButton(
           onPressed: () {
             Navigator.push(
               context,
               MaterialPageRoute(
                 builder: (context) => MyHomePage(),
               ),
             );
           },
           icon: Icon(Icons.arrow_forward_ios_outlined),
         ),
       ],
     ),
     floatingActionButton: FloatingActionButton(
       onPressed: () {
         Provider.of<ViewModel>(context, listen: false).fonksiyon();
       },
     ),
     body: Center(
       child: Consumer<ViewModel>(
         builder: (context, viewModel, child) {
           return viewModel.apiResponse.status == Status.completed 
               ? Text(viewModel.apiResponse.data) 
               : CircularProgressIndicator();
         },
       ),
     ),
   );
 }
}

内容的提问来源于stack exchange,提问作者Burak Dinç

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 07:55:34