百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

GetX框架里容易被忽略的那些小知识

myzbx 2025-09-24 00:42 3 浏览

在使用 GetxController(以及它的子类,如 GetxService)时,我们通常会接触到几个常见的生命周期方法,比如 onInit、onReady、onClose 等。实际上,GetX 在 Controller 的生命周期管理上提供了更细致的钩子函数,帮助我们更好地安排业务逻辑。

一、GetxController 主要生命周期方法

  • onInit()
  • onReady()
  • onClose()

这三大方法在 GetxController 中最常用,也是官方文档重点介绍的。除此之外,在 GetX 源码中还可以找到一些其他(比较少见)的生命周期方法,例如 onStart, onDelete, 以及对于 GetxService 的一些附加逻辑。

不过在常规的业务开发场景下,主要关注 onInit(), onReady() 和 onClose() 就足以应对绝大部分需求。

让我们依次了解它们在何时被调用、适合处理哪些逻辑,以及一些最佳实践。

1. onInit()

何时被调用?

  • 当 Controller 实例被 Get.put 或 Get.find(第一次获取)时,会立即调用该 Controller 的 onInit() 方法。
  • 这意味着 onInit() 通常是这个 Controller 生命周期的开端,一般在 Widget 构建之前就会执行(或者说,在页面渲染之前)。

适合处理的逻辑

  1. 变量初始化:初始化业务变量、Rx 变量等。
  2. 监听绑定:通过 ever, debounce, interval 等 Worker,在此处集中设置对 Rx 变量的监听。
  3. 依赖注入:如果这个控制器需要依赖某些服务(也可以用 Bindings),也可以在这里尝试使用 Get.find 获取并赋值。
  4. 轻量级网络请求:如果数据的优先级比较高,需要在页面显示之前就拿到(如基础配置、用户信息),可以在 onInit()里发请求。但如果请求会阻塞页面渲染过久,可以考虑放到 onReady()。
class HomeController extends GetxController {
var counter = 0.obs;
@override
void onInit() {
super.onInit();
print('onInit -> Controller开始初始化');
// 设置 Worker,比如监听 counter 的变化
ever(counter, (value) {
print('counter changed: $value');
});
// 如果需要请求一些不太大的数据,比如配置文件
fetchInitialData();
}
void fetchInitialData() {
// ...
}
}

注意:如果请求会比较耗时,且必须在页面完全渲染后才做,不建议放在 onInit(),否则用户可能在空白页面等待,体验不好。这时应该考虑放到 onReady()。

2. onReady()

何时被调用?

  • 当 Widget(绑定了该 Controller 的页面)渲染完成后,就会调用 onReady()。
  • 它比 onInit() 更晚,通常意味着页面已经可见,此时做一些需要依赖“页面可见”的操作会更合适。

适合处理的逻辑

  1. 网络请求 / 动画启动:页面渲染完成后,再开始长耗时操作或加载数据,可以先让用户看到页面框架,避免一直等待空白屏。
  2. 弹窗 / SnackBar:有时需要在页面刚显示时弹出引导或提示,也可以在这里调用。
  3. 启动轮询 / 计时器:页面已经加载完,可能需要周期性地更新数据。
class ProfileController extends GetxController {
var profile = Rxn<UserProfile>(); // 可能是null
@override
void onInit() {
super.onInit();
// 这里可以做一些很轻量的初始化
// 例如:profile.value = localCache?.readProfile();
}
@override
void onReady() {
super.onReady();
print('onReady -> 页面已经渲染完成');
// 进行相对耗时或需要页面已加载才执行的网络请求
fetchUserProfile();
}
void fetchUserProfile() async {
// ... 异步请求
// profile.value = ...
}
}

PS:有些人也喜欢把所有网络请求都放 onInit(),这样页面一进来就开始请求。并不是不可以,但若数据体量较大,则可能延迟页面的渲染,用户体验没有 onReady() 友好。

3. onClose()

何时被调用?

  • 当 Controller 所在的页面被销毁、或者我们主动调用了 Get.delete()(若此 Controller 未被其它依赖持有)时,会触发 onClose().
  • 在默认的 SmartManagement.full 模式下,离开页面并且路由不再保留时,就会自动销毁该 Controller 并调用 onClose()。

适合处理的逻辑

  1. 释放资源:例如取消订阅、关闭流、dispose Timer / Worker、断开 WebSocket 等。
  2. 保存数据:在页面关闭时,将一些状态持久化到本地或共享存储。
  3. 取消请求:如果有网络请求或异步操作在进行,可以在这里清理或取消。
class ChatController extends GetxController {
late final StreamSubscription messageSub;
@override
void onInit() {
super.onInit();
messageSub = ChatService.onNewMessage.listen((msg) {
// handle new message
});
}
@override
void onClose() {
// 页面销毁时,取消监听,避免内存泄漏
messageSub.cancel();
super.onClose();
}
}

注意:若你在 onInit() 或其他地方启动了定时器 (Timer)、stream 监听、socket 连接等,一定要在 onClose() 中主动释放,否则会出现内存泄漏或意外的后台执行。

二、其他较少见的生命周期/方法

onStart()

在部分早期版本或某些扩展中,可能会看到 onStart(),但在官方的最新控制器中并没有默认实现。onStart() 更类似于一个“刚开始启动 Controller”的时刻,一般你可以把它当作是比 onInit() 更早的一层(但通常我们不使用它)。

目前常见的场景会使用 onInit() 即可满足需求。若你要在生成 Controller 之后,还没正式初始化前执行某些事情,可以考虑直接在构造函数或 onInit() 里处理。

onDelete()

当使用 Get.delete(force: true) 时,可能会触发到 onDelete。它在 GetX 的内部封装里用来清理一些辅助资源。大多数时候你只需要在 onClose() 中进行资源释放即可。

三、在不同生命周期做什么业务最合适

下面做一个小结,可以作为一个通用的“对照表”:

生命周期方法

何时调用 & 适用场景

建议做的事

不建议做的事

onInit()

1. 当 Controller 被注入(或 Get.find 首次被调用)时触发
2. 页面构建前执行,属于 Controller 的初始化阶段

1. 绑定 Worker(ever, debounce, interval 等)
2. 依赖注入或 Get.find()
3. 轻量级数据准备(如同步读取、少量网络请求)
4. 做一些初步逻辑(设置默认值、读取缓存等)

1. 不要进行非常耗时的操作(会阻塞页面首帧渲染)
2. 不要在此处弹出对话框或执行大量 UI 操作(此时页面尚未渲染)

onReady()

1. 当页面(Widget)已完成渲染后触发
2. 比 onInit() 更晚,可确保用户已能看到页面主体

1. 加载大数据或较长耗时异步请求(确保页面不白屏)
2. 启动动画、弹出对话框或引导
3. 获取用户真正所需的核心数据(如详情、列表)
4. 启动定时器、轮询等(页面已可见,用户体验更好)

1. 不适合过早执行的操作(应放在 onInit() 中)
2. 如果某操作必须在页面显示前完成,放在 onInit() 但要注意影响首屏渲染,需平衡用户体验

onClose()

1. 当 Controller 被销毁或页面结束路由栈时触发
2. 在默认 SmartManagement.full 模式下,离开页面会销毁对应 Controller

1. 释放资源(如 Stream、Timer、WebSocket、Controller)
2. 保存页面状态或数据(写入本地或全局服务)
3. 取消未完成的网络请求(避免后台无用操作)

1. 避免过多耗时操作(用户已离开页面)
2. 不建议执行过于复杂的逻辑,可考虑改为后台异步执行或交给全局服务处理

四、完整实例

以下示例演示一个带有 Worker、网络请求、资源释放的 Controller,并在不同生命周期执行不同逻辑。

class ProductController extends GetxController {
// 产品列表
final products = <Product>[].obs;
// 搜索关键字
final searchQuery = ''.obs;
// 定时轮询的 timer
Timer? pollingTimer;
@override
void onInit() {
super.onInit();
print('ProductController -> onInit');
// 1. Worker - 监听搜索关键字变化,触发搜索
debounce(searchQuery, (_) {
fetchProducts(searchQuery.value);
}, time: Duration(milliseconds: 500));
// 2. 可以进行一些轻量级初始化操作,或者尝试用局部缓存
final cachedData = LocalCache.get('product_list');
if (cachedData != null) {
products.assignAll(cachedData);
}
}
@override
void onReady() {
super.onReady();
print('ProductController -> onReady');
// 页面已渲染,可以进行真正的网络请求
fetchProducts();
// 每 30 秒轮询一次数据
pollingTimer = Timer.periodic(Duration(seconds: 30), (timer) {
fetchProducts();
});
}
@override
void onClose() {
print('ProductController -> onClose');
// 1. 释放 Timer
pollingTimer?.cancel();
// 2. 可能需要保存最后的产品列表
LocalCache.save('product_list', products.toList());
// 3. 执行父类 onClose
super.onClose();
}
void fetchProducts([String? query]) async {
// ... 调接口获取产品列表
// products.value = ...
print('Fetching products with query: $query');
}
}
  • 在 onInit() 中,设置了 searchQuery 的去抖监听,并尝试加载本地缓存数据。
  • 在 onReady() 中,页面渲染完成后进行网络请求、启动定时轮询。
  • 在 onClose() 中,销毁 Timer 并保存数据到本地。

五、总结

onInit():

  • 适合做初始绑定、轻量初始化、Worker 监听
  • 时间点:Controller 被创建、注入后立即执行

onReady():

  • 适合在页面渲染后再做更多数据加载、动画启动、提示弹窗
  • 时间点:Widget build 完成后

onClose():

  • 适合资源释放、销毁定时器或保存数据
  • 时间点:页面或 Controller 被销毁前

合理利用 GetX Controller 的这些生命周期方法,可以让你的业务逻辑分层更加清晰、页面渲染和数据请求的时机更可控,也更便于管理资源和避免内存泄漏。

相关推荐

智能设备弹窗频发?3步教你彻底解决小v自动弹出困扰

创作声明:本文章原创,未经作者许可,禁止转载、摘编、复制及建立镜像。转载请注明出处,文章内容仅作参考,如有雷同,纯属巧合。图片和文字均不涉及真实人物和事件。在数字化浪潮席卷全球的今天,智能设备已成为我...

微软在Edge桌面搜索栏加入视觉搜索

IT之家9月16日消息,科技媒体WindowsReport今天(9月16日)发布博文,报道称在Canary频道最新MicrosoftEdge浏览器中,微软邀请Windo...

GetX框架里容易被忽略的那些小知识

在使用GetxController(以及它的子类,如GetxService)时,我们通常会接触到几个常见的生命周期方法,比如onInit、onReady、onClose等。实际上,GetX在...

充电宝弹出这种提示框,千万别点!

2025年国家网络安全宣传周现场展示了一批新型窃密工具一款可窃取手机数据的共享充电宝引起关注这些工具究竟是如何实施窃密的?又该如何防范?这款充电宝之所以能实现窃密,关键在于其内部搭载的一个特殊小零件。...

大屏可视化组态软件【数据绑定】_组态软件视频

写在前面:在最新的样式中,数据源和属性合并了成数据,以前的图纸数据会做转换处理。如果之前创建有多条数据源,默认会将之前的属性列表放到第一条数据源下面。如果没有建立一条数据源,之前的属性将不会展示到页...

如何关闭Win11触控板,轻松解决烦人的触摸问题

如何关闭Win11触控板,轻松解决烦人的触摸问题随着Windows11的发布,许多用户发现他们在使用新操作系统时遇到了触控板的问题。有时候触摸板可能会无故启动,导致一些不必要的麻烦和干扰。遇到这种情...

三星手机消息快捷窗口回复设置步骤,非常实用,可点赞收藏设置。

都说三星手机的使用功能像一本大字典,很多人用了好几年三星,其实三星很多功能都不会设置,也不知道。因此很多看三星用户都感叹,用了好几年三星手机,看到别人发的三星手机某个功能设置的时候,就感觉像白用三星手...

主板BIOS能识别2280固态硬盘,但系统里看不到怎么办?

在日常安装固态硬盘的过程中,许多用户都有一个疑虑:2280规格的M.2固态硬盘在主板BIOS中能够识别,但进入Windows系统后却无法看到。这个问题不仅令人困惑,还可能影响数据访问和系统安装。今天,...

WMS系统从入门到精通(十一)-原型图设计及逻辑实战-复核打包

复核打包是仓储管理系统中的关键环节,直接影响出库效率与准确率。本文通过原型图设计与业务逻辑实战,系统拆解WMS复核打包模块的核心流程与产品思考,为产品经理提供从0到1的落地参考。之前文章与大家分享了W...

第十八篇 如何解绑通信行程卡?为什么要解绑行程码?

今天讲的是如何解绑行程码?那么我们为什么要解绑行程码呢,因为行程码上有我们的姓名身份证甚至门牌号,解绑后可以降低我们的安全隐患。接下来我给大家演示一遍如何解绑行程码,第一步,打开支付宝,点击右下角“我...

注意!共享充电宝弹出这个提示框,千万别点!

2025年国家网络安全宣传周在云南昆明开幕,期间,网络安全博览会同步举行。博览会现场展示了一批新型窃密工具,这些工具究竟是如何实施窃密的?又该如何防范?下面展示了一款可窃取手机数据的共享充电宝。表面充...

五个不太为人知的ESC键妙用法_esc键的功能是什么意思啊

对于普通用户来说,位于键盘左上方的ESC键并非高频使用键。然而,你是否知晓,实际上借助ESC键能够实现诸多快捷操作呢?上网浏览时,倘若不慎点错某个网址,只需轻按ESC键,便能即刻停止当前网页的打开进程...

第三方登录不跳转!Safari 不支持,开发者懒省事,用户如何破局?

谁没经历过网页登录的糟心事儿?早年每个网站都要注册账号,密码记一堆,忘了还得找回;后来有了第三方登录,比如“用谷歌登”,以为解放了,结果新坑更隐蔽。靠第三方Cookie证明身份,这玩意儿同时被广...

笔记本电脑怎么快速查看 IP地址?_怎样查看笔记本的ip地址

使用笔记本电脑时,我们难免要查看电脑的IP地址,排查网络错误或设置局域网络共享,但对于不懂电脑的小白来说,根本不清楚如何快速查找网络IP地址。今天,小编就以Windows系统为例,介绍多种查询IP地址...

手把手教你用3 种实用方法 在SMART Line 触摸屏做用户登录

大家好呀~最近有朋友问我,做HMI项目时用户登录功能总搞不明白,尤其是用SMARTLine触摸屏和WinCCflexibleSMART软件的时候,总怕漏了哪个步骤。其实我刚开始接触的...