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

Flutter中调用dispose后使用EndUserViewModel报错求助

问题原因

你在initState里的mounted检查仅保证调用loadEndUser时组件存在,但fetchEndUser是异步API请求,请求完成时组件可能已被销毁,且EndUserViewModel也可能已执行dispose,此时再访问ViewModel就会触发报错。


解决方案

方案1:在异步操作关键节点检查状态

取消initState里多余的mounted判断(initState执行时组件必然处于挂载状态),在API请求前后、访问ViewModel属性前,分别检查组件和ViewModel的可用状态:

@override
void initState() {
  super.initState();
  loadEndUser(); // initState阶段组件一定处于mounted状态,无需额外判断
}

loadEndUser() async {
  WidgetsBinding.instance.addPostFrameCallback((_) async {
    // 检查组件是否仍挂载
    if (!mounted) return;

    // 获取ViewModel实例
    final endUserViewModel = ref.read(endUserViewModelProvider.notifier);
    // 检查ViewModel是否仍可用
    if (!endUserViewModel.mounted) return;

    // 执行异步API请求
    await endUserViewModel.fetchEndUser("user02@gmail.com");

    // 请求完成后再次检查状态
    if (!mounted || !endUserViewModel.mounted) return;

    // 访问ViewModel数据
    final endUser = endUserViewModel.endUserList;
    final endUserData = endUser?.first.name;
    print(" DATA $endUser");
    print("USER $endUserData");
  });
}

方案2:取消未完成的API请求(更彻底)

如果你的API请求使用Dio等支持取消的库,可以在组件销毁时主动取消请求,避免后续无效操作:

1. 修改ViewModel的fetchEndUser方法,支持取消令牌

class EndUserViewModel extends StateNotifier<EndUserState> {
  CancelToken? _fetchCancelToken;

  EndUserViewModel() : super(EndUserState.initial());

  Future<void> fetchEndUser(String email, {CancelToken? cancelToken}) async {
    _fetchCancelToken = cancelToken ?? CancelToken();
    try {
      // 示例:使用Dio发起请求并传入取消令牌
      final response = await Dio().get(
        'your-api-url/end-user',
        queryParameters: {'email': email},
        cancelToken: _fetchCancelToken,
      );
      // 更新ViewModel状态
      state = state.copyWith(endUserList: [...response.data]);
    } on DioException catch (e) {
      if (e.type == DioExceptionType.cancel) {
        // 请求被取消,直接返回不处理错误
        return;
      }
      // 处理其他API错误
      state = state.copyWith(error: e.message);
    } finally {
      _fetchCancelToken = null;
    }
  }

  @override
  void dispose() {
    // ViewModel销毁时取消未完成的请求
    _fetchCancelToken?.cancel("ViewModel已销毁");
    super.dispose();
  }
}

2. 在组件中管理取消令牌

CancelToken? _fetchCancelToken;

@override
void initState() {
  super.initState();
  loadEndUser();
}

loadEndUser() async {
  WidgetsBinding.instance.addPostFrameCallback((_) async {
    if (!mounted) return;

    _fetchCancelToken = CancelToken();
    final endUserViewModel = ref.read(endUserViewModelProvider.notifier);

    await endUserViewModel.fetchEndUser(
      "user02@gmail.com",
      cancelToken: _fetchCancelToken,
    );

    if (!mounted || !endUserViewModel.mounted) return;

    final endUser = endUserViewModel.endUserList;
    final endUserData = endUser?.first.name;
    print(" DATA $endUser");
    print("USER $endUserData");
  });
}

@override
void dispose() {
  // 组件销毁时取消未完成的请求
  _fetchCancelToken?.cancel("组件已销毁");
  super.dispose();
}

内容的提问来源于stack exchange,提问作者Farhana Akter

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 03:38:12