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

如何在GetxController中正确销毁infinite_scroll_pagination的PagingController?

解决GetxController销毁后异步任务访问已释放PagingController的异常问题

问题场景

我在使用Getx时,通过GetxController的onClose方法释放资源:

@override
void onClose() {
  pagingController.dispose();
  super.onClose();
}

但遇到了异常:控制器内的异步方法_fetchPage负责获取分页数据并更新pagingController,如果在该方法执行完成前离开页面,异步任务不会自动终止,等数据返回后调用已销毁的pagingController时,会抛出:

Unhandled Exception: Exception: A PagingController was used after being disposed.

_fetchPage方法代码如下:

Future<void> _fetchPage(int pageKey) async {
    try {
      var skip = pageKey == 0 ? 0 : (10 * pageKey);
      var data = await fetchDataOfPage(skip, limit);
      final isLastPage = data.length < limit;

      if (isLastPage) {
        pagingController.appendLastPage(data);
      } else {
        final nextPageKey = pageKey + 1;
        pagingController.appendPage(data, nextPageKey);
      }
    } catch (error) {
      pagingController.error = error;
    }
  }

解决方案

核心是在控制器销毁时终止未完成的异步任务,或在任务完成后先检查资源状态再执行操作,以下是两种可行方案:

方案1:用CancelToken取消异步请求(推荐)

如果你的fetchDataOfPage是基于Dio实现的网络请求,可以借助CancelToken直接终止请求,避免无效资源消耗:

  1. 在控制器中声明CancelToken:
class YourController extends GetxController {
  final CancelToken _requestCancelToken = CancelToken();
  late PagingController pagingController;

  // 其他初始化逻辑...
}
  1. 修改_fetchPage,传入CancelToken并增加状态检查:
Future<void> _fetchPage(int pageKey) async {
    try {
      var skip = pageKey == 0 ? 0 : (10 * pageKey);
      // 将CancelToken传入请求方法,内部用它控制请求生命周期
      var data = await fetchDataOfPage(skip, limit, cancelToken: _requestCancelToken);
      final isLastPage = data.length < limit;

      // 检查控制器是否已销毁,是则直接返回
      if (isClosed) return;

      if (isLastPage) {
        pagingController.appendLastPage(data);
      } else {
        final nextPageKey = pageKey + 1;
        pagingController.appendPage(data, nextPageKey);
      }
    } catch (error) {
      // 忽略请求取消的异常
      if (error is DioException && error.type == DioExceptionType.cancel) return;
      // 确认控制器存活再设置错误状态
      if (!isClosed) {
        pagingController.error = error;
      }
    }
  }
  1. 在onClose中取消请求并释放资源:
@override
void onClose() {
  // 取消所有未完成的请求
  _requestCancelToken.cancel("控制器已销毁,终止请求");
  pagingController.dispose();
  super.onClose();
}

方案2:用Getx自带的isClosed状态检查

如果不需要终止异步任务,也可以在任务完成后先检查控制器状态,确认未销毁再操作pagingController:

修改_fetchPage方法:

Future<void> _fetchPage(int pageKey) async {
    try {
      var skip = pageKey == 0 ? 0 : (10 * pageKey);
      var data = await fetchDataOfPage(skip, limit);
      final isLastPage = data.length < limit;

      // 关键:先检查控制器是否已关闭
      if (isClosed) return;

      if (isLastPage) {
        pagingController.appendLastPage(data);
      } else {
        final nextPageKey = pageKey + 1;
        pagingController.appendPage(data, nextPageKey);
      }
    } catch (error) {
      if (!isClosed) {
        pagingController.error = error;
      }
    }
  }

保留onClose的资源释放逻辑:

@override
void onClose() {
  pagingController.dispose();
  super.onClose();
}

额外说明

  • 如果fetchDataOfPage是自定义异步操作(非Dio请求),可以自己实现取消机制:比如声明bool _isDisposed变量,在onClose时设为true,在_fetchPage中检查该变量。
  • 优先选择方案1,能直接终止无效请求,减少不必要的资源消耗。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 20:45:58