Flutter GetX中GetxController的onReady为何在onInit后延迟?
GetX中onInit与onReady执行间隔过长的原因与解决办法
问题场景
我正在使用Flutter结合GetX框架开发,编写了如下TimerController:
class TimerController extends GetxController { int secondsRemaining = 5; late Timer timer; void startTimer() { timer = Timer.periodic(Duration(seconds: 1), (Timer t) { update(); }); } @override void onInit() { print('${DateTime.now()}'); print("onInit"); super.onInit(); } @override void onReady() { print("onReady"); print('${DateTime.now()}'); super.onReady(); } }
并在页面中按如下方式使用该控制器:
class _PageState extends State<Page> { TimerController timerController = Get.put(TimerController()); @override Widget build(BuildContext context) { return GetBuilder<TimerController>( initState: (data) => timerController.startTimer(), dispose: (_) => timerController.stopTimer(), builder: (controller) { return Text('${timerController.secondsRemaining}s'); }, ) } }
路由跳转后,日志显示onInit与onReady的执行间隔约2秒:
[GETX] GOING TO ROUTE /Page [GETX] Instance "TimerController" has been created I/flutter ( 6948): 2023-11-21 17:53:54.057766 I/flutter ( 6948): onInit [GETX] Instance "TimerController" has been initialized I/flutter ( 6948): onReady I/flutter ( 6948): 2023-11-21 17:53:56.379983
即使注释掉Timer相关代码,延迟问题依然存在。请问该问题产生的原因是什么,如何解决?
原因分析
问题核心在于控制器初始化时机过早:你在State的成员变量中直接调用Get.put(TimerController()),这会让控制器在State创建阶段就完成初始化(触发onInit),但此时页面的Widget树尚未构建完成。直到build方法执行并渲染GetBuilder组件时,GetX才会触发控制器的onReady方法,两者的时间差就是页面Widget构建、渲染的耗时,因此出现了2秒左右的间隔。
这种写法还会导致控制器生命周期与页面State不同步,可能引发不必要的性能损耗或内存泄漏风险。
解决办法
1. 让GetBuilder统一管理控制器初始化
将控制器的初始化移到GetBuilder的init参数中,由GetX管控控制器的生命周期,确保onInit和onReady的执行时机更贴合:
class _PageState extends State<Page> { @override Widget build(BuildContext context) { return GetBuilder<TimerController>( init: TimerController(), // 在此处初始化控制器 initState: (data) => data.startTimer(), dispose: (_) => _.stopTimer(), builder: (controller) { return Text('${controller.secondsRemaining}s'); }, ); } }
2. 延迟获取控制器(适用于需要在State中调用控制器方法的场景)
如果必须在State中持有控制器实例,不要在成员变量中直接初始化,而是在initState方法中完成控制器的获取,确保页面初始化后再创建控制器:
class _PageState extends State<Page> { late TimerController timerController; @override void initState() { super.initState(); // 页面初始化阶段完成控制器注入 timerController = Get.put(TimerController()); } @override Widget build(BuildContext context) { return GetBuilder<TimerController>( initState: (data) => timerController.startTimer(), dispose: (_) => timerController.stopTimer(), builder: (controller) { return Text('${controller.secondsRemaining}s'); }, ); } }
3. 完善控制器的生命周期方法(避免内存泄漏)
你的控制器缺少stopTimer方法,且未在onClose中处理定时器,补充后可避免内存泄漏:
class TimerController extends GetxController { int secondsRemaining = 5; late Timer timer; void startTimer() { timer = Timer.periodic(const Duration(seconds: 1), (Timer t) { if (secondsRemaining > 0) { secondsRemaining--; update(); } else { timer.cancel(); } }); } void stopTimer() { timer.cancel(); // 取消定时器 } @override void onInit() { print('${DateTime.now()}'); print("onInit"); super.onInit(); } @override void onReady() { print("onReady"); print('${DateTime.now()}'); super.onReady(); } @override void onClose() { stopTimer(); // 控制器销毁时自动清理定时器 super.onClose(); } }
通过以上修改,控制器的onInit与onReady执行间隔会大幅缩短,同时能保证控制器生命周期与页面同步,避免潜在的内存泄漏问题。
内容的提问来源于stack exchange,提问作者magic_9527
相关产品推荐
相关产品推荐

