【Flutter】基于 GetX 实现 Dio 的生命周期自动化

前言

在前文【传送门】的网络请求封装中我们基于DIO的网络请求进行了封装,本身是没什么问题的,但是细想之下,我们并没有处理取消网络的逻辑。

在之前客户端的开发中,例如 Android 的 ViewModel 中我们不管是通过协程的绑定生命周期自动取消,还是使用 RxJava/RxKotlin 的方式手动收集 Disposable 并且在销毁的时候释放,我们都是需要做处理的。

而在 Flutter 中由于我们是基于 Get 框架实现的,那么在 GetxController 中我们并没有处理网络请求的取消,这样就可能会发生内存泄露、占用带宽和系统资源、空指针等。

所以我们需要考虑如何在 GetxController 中实现自动化的 DIO 的 CancelTag 管理。

实现的方式有很多,这里列举三种方式:一种是我们常用的基类封装,另一种是使用扩展方法实现,还有一种是混入实现,下面就分别看看如何实现吧。

一、基类的实现

其实我个人不推荐这种方法,不太优雅,因为可能我们自己封装了一个 BaseController 除了你自己其他人接触到你的项目就是一脸懵,直接改变了原本类,容易让人摸不着头脑。

scala 复制代码
import 'package:dio/dio.dart';
import 'package:get/get.dart';

class BaseController extends GetxController {
  // Dio 实例可以从外部传入,也可以在BaseController中创建
  final Dio dio;
  // 创建一个 CancelToken 用于取消Dio请求
  final CancelToken cancelToken = CancelToken();
  
  BaseController({required this.dio});

  @override
  void onClose() {
    // 当控制器关闭时,取消所有的 Dio 请求
    cancelToken.cancel("Controller has been disposed");
    super.onClose();
  }
  
  // 其他公共方法或属性 ...
}

使用的时候:

scala 复制代码
class MyController extends BaseController {
  MyController({required Dio dio}) : super(dio: dio);

  void fetchData() async {
    try {
      final response = await dio.get(
        'https://example.com/data',
        cancelToken: cancelToken,
      );
      // 处理响应 ...
    } catch (e) {
      if (CancelToken.isCancel(e)) {
        print("请求取消:$e");
      } else {
        // 处理其他错误 ...
      }
    }
  }
  
  // 其他方法 ...
}

此时就是所有的 Controller 都需要继承你自定义的 BaseController,以后有什么逻辑就往 Base 里面加,反正能实现我的需求了。

二、扩展实现

使用扩展可能实现类似的功能,并且没有改变本身的 Controller 是继承与 GetxController 这个对象,让同事或者其他开发者一目了然。

但是缺点是扩展的逻辑不明显,如果你不告诉其他开发者,它甚至都不知道你在里面添加了什么逻辑,如果是 CancelToken 这种无感逻辑还好,如果是一些特定的逻辑或者有一些Bug坑,那真是找都不好找。

java 复制代码
import 'package:dio/dio.dart';
import 'package:get/get.dart';

extension CancelableGetController on GetxController {
  // 关联 CancelToken
  CancelToken _cancelToken = CancelToken();

  // 获取CancelToken的方法
  CancelToken get cancelToken => _cancelToken;

  // 取消请求的方法
  void cancelRequests() {
    _cancelToken.cancel("请求被取消");
  }

  // 为了确保自动取消网络请求,在类销毁时调用cancelRequests
  @override
  void onClose() {
    cancelRequests();
    super.onClose();
  }
}

我们使用扩展就无需使用 BaseController 了:

scala 复制代码
class MyController extends GetxController {
  final Dio dio = Dio();

  void fetchSomething() async {
    try {
      final response = await dio.get(
        'https://myapi.com/data',
        cancelToken: cancelToken, // 使用扩展提供的CancelToken
      );
      // 处理响应
    } catch (e) {
      // 错误处理
    }
  }
}

可以说是使用简单,逻辑无感,适用与一些特定场景。

三、混入实现

使用 mixin 的方式呢,和扩展比较类似,只是可以选装了,比如我这个 SettingController 它没有网络请求,只有一些本地数据处理逻辑,那么我就可以选择不混入 DIO 的 CancelToken 逻辑,如果我是 UserProfileController 这肯定是有网络请求我就可以选择混入DIO 的 CancelToken 逻辑。

可选装是他最大的有点,其他开发者可能一目了然,哦,你这个 Controller 加了一些奇怪的逻辑,他就能点进去看看你的混入逻辑,比较方便调试。

dart 复制代码
import 'package:dio/dio.dart';
import 'package:get/get.dart';

mixin CancelableMixin on GetxController {
  CancelToken _cancelToken = CancelToken();

  CancelToken get cancelToken => _cancelToken;

  @override
  void onClose() {
    _cancelToken.cancel("请求被取消");
    super.onClose();
  }
}

使用的时候:

scala 复制代码
class MyController extends GetxController with CancelableMixin {
  final Dio dio = Dio();

  void fetchSomething() async {
    try {
      final response = await dio.get(
        'https://myapi.com/data',
        cancelToken: cancelToken,
      );
      // 处理响应
    } catch (e) {
      // 错误处理
    }
  }
}

总结

三种方式都可以实现类似的效果,如果你就像使用基类完全没问题,如果你想隐藏你的业务逻辑使用扩展的方法很难被人发现,如果你想做成可配置的效果,更加极限的内存优化,那么使用混入的方式比较适合你。

什么?我用的哪一种?我用的混入方式,不过我在魔改 GetxController 其他方式也用到了扩展方法,对于一些必须存在的自定义且无感的逻辑我还是喜欢用扩展的方式,如果是可用可不用这种配置选项我更喜欢用混入的方式。

那么本期内容就到这里,如讲的不到位或错漏的地方,希望同学们可以评论区指出。

本文的代码已经全部贴出,部分没贴出的代码可以在前文中找到,我的 Flutter Demo 项目正在整理中,后期开源了会更新文章链接。

如果感觉本文对你有一点点的启发,还望你能点赞支持一下,你的支持是我最大的动力啦!

Ok,这一期就此完结。

相关推荐
C语言魔术师11 分钟前
【小游戏篇】三子棋游戏
前端·算法·游戏
匹马夕阳1 小时前
Vue 3中导航守卫(Navigation Guard)结合Axios实现token认证机制
前端·javascript·vue.js
你熬夜了吗?1 小时前
日历热力图,月度数据可视化图表(日活跃图、格子图)vue组件
前端·vue.js·信息可视化
桂月二二8 小时前
探索前端开发中的 Web Vitals —— 提升用户体验的关键技术
前端·ux
hunter2062069 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
qzhqbb9 小时前
web服务器 网站部署的架构
服务器·前端·架构
刻刻帝的海角9 小时前
CSS 颜色
前端·css
九酒9 小时前
从UI稿到代码优化,看Trae AI 编辑器如何帮助开发者提效
前端·trae
浪浪山小白兔10 小时前
HTML5 新表单属性详解
前端·html·html5
lee57610 小时前
npm run dev 时直接打开Chrome浏览器
前端·chrome·npm