在Flutter开发中,GetX
是一个非常强大的库,特别是它的依赖注入(DI)功能。依赖注入不仅简化了状态管理和服务的获取,还使得应用更加模块化,易于测试。本文通过实例深入讲解GetX依赖注入的应用。
GetX的依赖注入:
Get.put()
应用于全局服务或控制器,例如主题管理器,这些服务在整个应用的生命周期中都是必要的。Get.lazyPut()
它不会立即创建依赖,而是提供了一个“工厂函数”,只有在第一次使用 Get.find() 查找依赖时,该依赖才会被实例化。Get.putAsync()
适用于需要异步操作来初始化的服务, 它允许你在依赖项的创建过程中执行异步操作(例如网络请求),然后将异步创建的对象注册为依赖。例如数据库服务,这些服务在应用启动时进行异步初始化。
简单计数器
1 | class CounterController extends GetxController { |
在父Widget
注入
1 | class Home extends StatelessWidget { |
子Widget
中使用,可以直接继承StatelessWidget
无状态
1 | class CounterWidget extends StatelessWidget { |
多Widget
复用也一样的操作
1 | class CounterController extends GetxController { |
关于permanent参数
Get.put和Get.lazyput有个permanent参数。默认为false。
我们以Get.put为例子展开。
在 GetX 框架中,Get.put 方法用于将一个依赖(通常是一个控制器)注入到 Get 的依赖注入系统中。permanent 参数在这里起到一个关键的作用。它是一个布尔值,用于确定注入的依赖是否应该是“永久”的,即是否在路由导航时保持活跃状态。这里是它的两个主要用途:
在 GetX 框架中,Get.put 方法用于将一个依赖(通常是一个控制器)注入到 Get 的依赖注入系统中。permanent 参数在这里起到一个关键的作用。它是一个布尔值,用于确定注入的依赖是否应该是“永久”的,即是否在路由导航时保持活跃状态。这里是它的两个主要用途:
防止依赖被自动移除
当 permanent 设置为 true 时,注入的依赖不会在 Get 的路由导航(如页面跳转)时被自动移除。这对于需要跨多个页面共享的全局状态或服务(例如用户身份验证状态、主题设置、网络服务等)特别有用。
1 | // 全局注册一个控制器,它将不会因为路由变化而被移除 |
在上面的例子中,GlobalController 将保持在整个应用的生命周期内活跃,即使在页面之间导航时也不会被 Get 自动销毁。
普通依赖注入
如果 permanent 设置为 false(默认值),那么注入的依赖将在它不再被需要时自动被移除。这种行为通常用于页面或控制器特定的依赖,它们只在当前路由或页面中有效。
1 | // 注册一个非永久控制器 |
在这个例子中,HomeController 可能仅用于首页,并且当用户离开首页时,HomeController 可能会从内存中移除以节省资源。(controller的onClose方法可以监听离开页面,GetObserver也可以)
是否将依赖设置为永久性(permanent: true)取决于你的需求和依赖的用途。
使用Bindings来管理依赖
GetX还提供了Bindings类来集中管理依赖。这对于大型应用来说非常有用,因为它可以将依赖的注册和配置与UI逻辑分离。
创建绑定
我们创建一个CounterBinding来注册CounterController。
1 | class CounterBinding extends Bindings { |
使用绑定
在路由中,我们指定CounterBinding来在页面构建前完成依赖注入。
1 | GetPage( |
GetxController 主要生命周期方法
- onInit()
- onReady()
- onClose()
这三大方法在 GetxController 中最常用,也是官方文档重点介绍的。除此之外,在 GetX 源码中还可以找到一些其他的生命周期方法,例如 onStart, onDelete, 以及对于 GetxService 的一些附加逻辑。在常规的业务开发场景下,主要关注上述三个就足以应对绝大部分需求。
onInit
何时被调用?
当 Controller 实例被 Get.put 或 Get.find(第一次获取)时,会立即调用该 Controller 的 onInit() 方法。
这意味着 onInit() 通常是这个 Controller 生命周期的开端,一般在 Widget 构建之前就会执行(或者说,在页面渲染之前)。
适合处理的逻辑
- 变量初始化:初始化业务变量、Rx 变量等。
- 监听绑定:通过ever,debounce,interval等 Worker,在此处集中设置对 Rx 变量的监听。
- 依赖注入:如果这个控制器需要依赖某些服务(也可以用 Bindings),也可以在这里尝试使用 Get.find 获取并赋值。
- 轻量级网络请求:如果数据的优先级比较高,需要在页面显示之前就拿到(如基础配置、用户信息),可以在 onInit()里发请求。但如果请求会阻塞页面渲染过久,可以考虑放到 onReady()。
onReady
何时被调用?
当 Widget(绑定了该 Controller 的页面)渲染完成后,就会调用 onReady()。
它比 onInit() 更晚,通常意味着页面已经可见,此时做一些需要依赖“页面可见”的操作会更合适。
适合处理的逻辑
网络请求 / 动画启动:页面渲染完成后,再开始长耗时操作或加载数据,可以先让用户看到页面框架,避免一直等待空白屏。
弹窗 / SnackBar:有时需要在页面刚显示时弹出引导或提示,也可以在这里调用。
启动轮询 / 计时器:页面已经加载完,可能需要周期性地更新数据。
onClose
何时被调用?
当 Controller 所在的页面被销毁、或者我们主动调用了 Get.delete()(若此 Controller 未被其它依赖持有)时,会触发 onClose().
在默认的 SmartManagement.full 模式下,离开页面并且路由不再保留时,就会自动销毁该 Controller 并调用 onClose()。
适合处理的逻辑
释放资源:例如取消订阅、关闭流、dispose Timer / Worker、断开 WebSocket 等。
保存数据:在页面关闭时,将一些状态持久化到本地或共享存储。
取消请求:如果有网络请求或异步操作在进行,可以在这里清理或取消。
1 | class ProductController extends GetxController { |
小结
onInit
适合做初始绑定、轻量初始化、Worker 监听
时间点:Controller 被创建、注入后立即执行
onReady
适合在页面渲染后再做更多数据加载、动画启动、提示弹窗
时间点:Widget build 完成后
onClose
适合资源释放、销毁定时器或保存数据
时间点:页面或 Controller 被销毁前
合理利用 GetX Controller 的这些生命周期方法,可以让你的业务逻辑分层更加清晰、页面渲染和数据请求的时机更可控,也更便于管理资源和避免内存泄漏。