Flutter Get CLI项目中onInit函数失效问题求助
Controller的onInit无法执行的成因及解决方法
问题描述
用Get CLI创建Flutter应用后,发现Controller中的onInit函数无法正常执行,只有在View中用GetBuilder包裹并手动初始化Controller才能解决,但应用内页面过多,无法逐个修改,询问问题成因。
相关代码
Binding代码
import 'package:get/get.dart'; import '../controllers/login_controller.dart'; class LoginBinding extends Bindings { @override void dependencies() { Get.lazyPut<LoginController>( () => LoginController(), ); } }
Controller代码
import 'package:get/get.dart'; class LoginController extends GetxController { final count = 0.obs; @override void onInit() { print('but i work fine'); super.onInit(); } @override void onReady() { super.onReady(); } @override void onClose() { super.onClose(); } void increment() => count.value++; }
原View代码(onInit失效)
import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../../../routes/app_pages.dart'; import '../controllers/login_controller.dart'; class LoginView extends GetView<LoginController> { const LoginView({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( resizeToAvoidBottomInset: false, body: Padding( padding: const EdgeInsets.all(16.0), child: Center( child: SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'EVIDENCIA', style: TextStyle( fontSize: 32, fontWeight: FontWeight.bold, color: Colors.blue, ), ), SizedBox(height: 8), Text( 'Evidence based history taking', style: TextStyle( fontSize: 18, color: Colors.black54, ), ), SizedBox(height: 16), Text( 'be with us', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.black87, ), ), SizedBox(height: 32), TextField( decoration: InputDecoration( labelText: 'Username', border: OutlineInputBorder(), ), ), SizedBox(height: 16), TextField( decoration: InputDecoration( labelText: 'Password', border: OutlineInputBorder(), ), obscureText: true, ), SizedBox(height: 24), ElevatedButton( onPressed: () {}, style: ElevatedButton.styleFrom( backgroundColor: Colors.blue, minimumSize: Size(double.infinity, 50), ), child: Text('login'), ), SizedBox(height: 24), Text( 'evidencia.com', style: TextStyle( fontSize: 16, color: Colors.black54, ), ), SizedBox(height: 16), GestureDetector( onTap: () { Get.offAndToNamed(Routes.REGISTER); }, child: Text( 'register', style: TextStyle( fontSize: 16, color: Colors.blue, decoration: TextDecoration.underline, ), ), ), ], ), ), ), ), ); } }
修复后的View代码(onInit生效)
import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../../../routes/app_pages.dart'; import '../controllers/login_controller.dart'; class LoginView extends GetView<LoginController> { const LoginView({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return GetBuilder<LoginController>( init: LoginController(), builder: (controller) { return Scaffold( resizeToAvoidBottomInset: false, body: Padding( padding: const EdgeInsets.all(16.0), child: Center( child: SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'EVIDENCIA', style: TextStyle( fontSize: 32, fontWeight: FontWeight.bold, color: Colors.blue, ), ), SizedBox(height: 8), Text( 'Evidence based history taking', style: TextStyle( fontSize: 18, color: Colors.black54, ), ), SizedBox(height: 16), Text( 'be with us', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.black87, ), ), SizedBox(height: 32), TextField( decoration: InputDecoration( labelText: 'Username', border: OutlineInputBorder(), ), ), SizedBox(height: 16), TextField( decoration: InputDecoration( labelText: 'Password', border: OutlineInputBorder(), ), obscureText: true, ), SizedBox(height: 24), ElevatedButton( onPressed: () {}, style: ElevatedButton.styleFrom( backgroundColor: Colors.blue, minimumSize: Size(double.infinity, 50), ), child: Text('login'), ), SizedBox(height: 24), Text( 'evidencia.com', style: TextStyle( fontSize: 16, color: Colors.black54, ), ), SizedBox(height: 16), GestureDetector( onTap: () { Get.offAndToNamed(Routes.REGISTER); }, child: Text( 'register', style: TextStyle( fontSize: 16, color: Colors.blue, decoration: TextDecoration.underline, ), ), ), ], ), ), ), ), ); }); } }
问题成因
- 懒加载触发条件未满足:Binding中使用
Get.lazyPut注册Controller,这是懒加载模式——只有当Controller被首次访问(比如调用其属性、方法,或通过Get.find()、状态控件获取)时,才会实例化Controller并执行onInit。 - GetView未触发实例化:原View继承
GetView<LoginController>,仅提供了controllergetter,但整个View的build方法中没有任何地方实际访问这个controller(没有用它的变量、方法,也没有绑定状态控件),所以Get.lazyPut的实例化条件未触发,Controller从未被创建,onInit自然不会执行。 - GetBuilder手动初始化的作用:使用
GetBuilder并传入init: LoginController()时,会手动创建Controller实例,此时onInit会被执行,但这种方式会创建新的Controller实例,和Binding中注册的不是同一个,属于临时解决方法,存在实例不一致的隐患。
无需逐个修改页面的解决方法
- 方案1:主动触发懒加载:在View的build方法开头添加一行
final _ = controller;,主动访问Controller,触发Get.lazyPut的实例化逻辑,无需修改页面结构。 - 方案2:改用立即初始化:将Binding中的
Get.lazyPut改为Get.put,这样路由跳转时Binding执行后会立即实例化Controller,直接触发onInit,不需要等待访问。注意Get.put是立即初始化,适合需要提前执行初始化逻辑的场景。 - 方案3:检查路由绑定:确认
AppPages中对应路由是否正确绑定了LoginBinding,确保路由跳转时Binding被执行,Controller被正确注册。
内容的提问来源于stack exchange,提问作者RJ84
相关产品推荐
相关产品推荐

