什么是依赖注入?
依赖:就是类与类之间的关系,比如 Controller
依赖一个 Service
。
注入:就是把某个对象的实例交给一个容器(GetX 提供的全局管理器)来保存,需要的时候再从容器里拿,而不是自己手动 new
。
好处:
- 避免到处
new
对象,生命周期不好管理。 - 统一管理依赖,方便复用、懒加载、释放内存。
- 解耦,代码更清晰
GetX的注入方式
Get.put()
final controller = Get.put(CountController());
- 立即创建并注入到内存。
- 下次需要时直接从容器里拿,而不是重新创建。
- 默认情况下,它会在
Controller
不再使用时销毁(除非设为permanent: true
)。
使用场景:你确定马上要用到的对象。
Get.lazyPut()
Get.lazyPut<CountController>(() => CountController());
- 懒加载:只有在第一次
Get.find()
的时候才会创建对象。 - 适合比较“重”的对象,不需要一开始就创建。
使用场景:可能要用,但不一定马上用的对象。
Get.putAsync()
putAsync的函数声明
Future<S> putAsync<S>(AsyncInstanceBuilderCallback<S> builder,
{String? tag, bool permanent = false}) async =>
GetInstance().putAsync<S>(builder, tag: tag, permanent: permanent);
这个方法如果不要箭头函数简化:
Future<S> putAsync<S>(AsyncInstanceBuilderCallback<S> builder,
{String? tag, bool permanent = false}) async {
return GetInstance().putAsync<S>(builder, tag: tag, permanent: permanent);
}
这里的 async
其实是 可以省略 的,因为:
- 这个函数里面没有用
await
。 - 直接返回的就是一个
Future<S>
。
Future<S> putAsync<S>(AsyncInstanceBuilderCallback<S> builder,
{String? tag, bool permanent = false}) {
return GetInstance().putAsync<S>(builder, tag: tag, permanent: permanent);
}
putAsync
:这实际上是一个异步的方法
Future<S>
: 方法返回值putAsync
: 方法名<S>
:声明的泛型putAsync
这个异步方法的参数:(builder,{String? tag, bool permanent = false})
- 其中:
AsyncInstanceBuilderCallback<S> builder
是一个异步回调函数。回调函数是在Get.putAsync()
时执行。 {String? tag, bool permanent = false}
是可选参数。
- 其中:
案例
class DatabaseService {
Future<DatabaseService> init() async {
// 模拟初始化耗时
await Future.delayed(const Duration(seconds: 2));
print("DatabaseService 初始化完成");
return this;
}
}
class ApiService {
Future<ApiService> setup() async {
// 模拟初始化耗时
await Future.delayed(const Duration(seconds: 3));
print("ApiService 初始化完成");
return this;
}
}
class CacheService {
Future<CacheService> init() async {
// 模拟缓存服务初始化
await Future.delayed(const Duration(seconds: 1));
print("CacheService 初始化完成");
return this;
}
}
Future<void> main() async {
print("应用启动中...");
// 并行启动三个服务,而不是一个一个等
final dbFuture = Get.putAsync<DatabaseService>(
() async => DatabaseService().init(),
);
final apiFuture = Get.putAsync<ApiService>(() async => ApiService().setup());
final cacheFuture = Get.putAsync<CacheService>(
() async => CacheService().init(),
);
// 这期间你还能做同步的事情,比如注册一个不用异步的配置服务
Get.put<String>("AppConfig 已注册");
print("AppConfig 已注册"); // 这个是同步的
// 等待所有服务准备好
await Future.wait([dbFuture, apiFuture, cacheFuture]);
print("所有异步服务已准备就绪 ✅");
// 现在就能安全拿到实例
final db = Get.find<DatabaseService>();
final api = Get.find<ApiService>();
final cache = Get.find<CacheService>();
print("拿到数据库实例: $db");
print("拿到API实例: $api");
print("拿到缓存实例: $cache");
print("应用启动完成!");
}
日志:
I/flutter ( 5091): 应用启动中...
I/flutter ( 5091): AppConfig 已注册
[GETX] Instance "String" has been created
D/ProfileInstaller( 5091): Installing profile for com.example.getx_quickstart_learn
I/flutter ( 5091): CacheService 初始化完成
[GETX] Instance "CacheService" has been created
I/flutter ( 5091): DatabaseService 初始化完成
[GETX] Instance "DatabaseService" has been created
I/flutter ( 5091): ApiService 初始化完成
[GETX] Instance "ApiService" has been created
I/flutter ( 5091): 所有异步服务已准备就绪 ✅
I/flutter ( 5091): 拿到数据库实例: Instance of 'DatabaseService'
I/flutter ( 5091): 拿到API实例: Instance of 'ApiService'
I/flutter ( 5091): 拿到缓存实例: Instance of 'CacheService'
I/flutter ( 5091): 应用启动完成!
回调函数:() async => await DatabaseService().init(),
。这是一个匿名函数。完整的函数是:
() async {
final service = DatabaseService().init();
return service;
}
当你调用 Get.putAsync()
时,GetX 并不会立刻就有一个现成的对象,而是会马上执行你传入的 builder
回调,并等待它返回一个实例(Future<S>
)。
DatabaseService().init()
:创建一个DatabaseService()
的实例,并执行init()
方法。注意init()
方法里面把DatabaseService()
这个实例又返回给Gex
,让它可以注册到容器中。
class DatabaseService {
Future<DatabaseService> init() async {
// 模拟初始化耗时
await Future.delayed(const Duration(seconds: 2));
print("DatabaseService 初始化完成");
return this;
}
}
Get.putAsync()
与其他注入方式最大的不同就是它返回的是一个Future<S>
。所有它可以异步处理很多事情。
然后再统一一个时间点等待
// 等待所有服务准备好
await Future.wait([dbFuture, apiFuture, cacheFuture]);
使用场景:
依赖需要异步初始化。
- 数据库(如 SQLite)初始化
- SharedPreferences / Hive 的异步加载
- 需要网络请求才能构造的对象
Get.create()
Get.create<CountController>(() => CountController());
final controller1 = Get.find<CountController>();
final controller2 = Get.find<CountController>();
controller1
和 controller2
不是同一个对象,因为 Get.find
每次都会 new 一个。
Get.create
都是“工厂模式”,每次 Get.find
都会新建实例。
tag的作用
在 GetX 依赖注入里,tag
就是 “名字标签”,用来区分 相同类型 的不同实例。
为什么需要 tag
- 如果你在容器里注册了多个 同类型 的对象(比如两个
ApiService
), - 但你又想分别获取它们,就必须用
tag
来区分。 - 否则
Get.find<ApiService>()
就会报错:“找到多个实例,不知道要返回哪个”。
对于Get.create
的行为,不管有没有 tag
,Get.create
都是“工厂模式”,每次 Get.find
都会新建实例。因为tag
只是为了区分多个不同的注册(防止冲突),不会改变它“每次都创建新对象”的机制。
class MyService {
final String name;
MyService(this.name);
}
class MyService2 {
final String name;
MyService2(this.name);
}
class MyService3 {
final String name;
MyService3(this.name);
}
class MyService4 {
final String name;
MyService4(this.name);
}
void main() {
// ------------------ 1. Get.put 单例 ------------------
// 注册一个单例
Get.put<MyService>(MyService("Singleton Service"));
// 多次获取,看看 hashCode 是否相同
final s1 = Get.find<MyService>();
final s2 = Get.find<MyService>();
print("=== Get.put 单例 ===");
// s1: Singleton Service, hashCode: 670782972
print("s1: ${s1.name}, hashCode: ${s1.hashCode}");
// s2: Singleton Service, hashCode: 670782972
print("s2: ${s2.name}, hashCode: ${s2.hashCode}");
// 是否是同一个实例: true
print("是否是同一个实例: ${identical(s1, s2)}");
print("");
// ------------------ 2. Get.create 工厂模式 ------------------
// 注册一个工厂,每次都会创建新的对象
Get.create<MyService2>(() => MyService2("Factory Service"));
final c1 = Get.find<MyService2>();
final c2 = Get.find<MyService2>();
print("=== Get.create 工厂模式 ===");
// c1: Factory Service, hashCode: 506914086
print("c1: ${c1.name}, hashCode: ${c1.hashCode}");
// c2: Factory Service, hashCode: 885138364
print("c2: ${c2.name}, hashCode: ${c2.hashCode}");
// 是否是同一个实例: false
print("是否是同一个实例: ${identical(c1, c2)}");
// ------------------ 3. Get.create 工厂模式 带 tag------------------
Get.create<MyService3>(() => MyService3("Factory Service"), tag: "myTag");
final c3 = Get.find<MyService3>(tag: "myTag");
final c4 = Get.find<MyService3>(tag: "myTag");
print("=== Get.create 工厂模式 带 tag ===");
// c3: Factory Service, hashCode: 992340179
print("c3: ${c3.name}, hashCode: ${c3.hashCode}");
// c4: Factory Service, hashCode: 451596084
print("c4: ${c4.name}, hashCode: ${c4.hashCode}");
// 是否是同一个实例: false
print("是否是同一个实例: ${identical(c3, c4)}");
// ------------------ 4. Get.put 单例 带 tag ------------------
Get.put<MyService4>(MyService4("Singleton Service"), tag: "getTag1");
Get.put<MyService4>(MyService4("Singleton Service"), tag: "getTag2");
final s3 = Get.find<MyService4>(tag: "getTag1");
final s4 = Get.find<MyService4>(tag: "getTag2");
final s5 = Get.find<MyService4>(tag: "getTag2");
print("=== Get.put 单例 带 tag ===");
// s3: Singleton Service, hashCode: 385559188
print("s3: ${s3.name}, hashCode: ${s3.hashCode}");
// s4: Singleton Service, hashCode: 693402719
print("s4: ${s4.name}, hashCode: ${s4.hashCode}");
// s5: Singleton Service, hashCode: 693402719
print("s5: ${s5.name}, hashCode: ${s5.hashCode}");
// 不同tag是不是同一个实例: false
print("不同tag是不是同一个实例: ${identical(s3, s4)}");
// 相同tag是不是同一个实例: true
print("相同tag是不是同一个实例: ${identical(s4, s5)}");
// 如果在单例模式下,创建了多个实例,但是不用tag去取,那么就会报错
// final s6 = Get.find<MyService4>();
// "MyService4" not found. You need to call "Get.put(MyService4())" or "Get.lazyPut(()=>MyService4())"
}
查找依赖
使用 Get.find<T>()
来获取注入的对象。如果没找到,就会抛异常
final controller = Get.find<CountController>();
Get.isRegistered<T>()
:判断某个类型是否已经注册。
if (Get.isRegistered<HomeController>()) {
print("已注册");
}
Get.isPrepared<T>()
:判断依赖是否准备好(即是否已经实例化)。
if (Get.isPrepared<HomeController>()) {
print("已准备好实例");
}
删除依赖
Get.delete<CountController>(); // 删除某个依赖
Get.reset(); // 重置所有依赖和路由状态,类似“重启”。
Get.deleteAll() // 删除所有依赖
常用于退出页面或切换用户时。
生命周期回调
任何继承 GetxController
的类都有生命周期:
class HomeController extends GetxController {
@override
void onInit() {
super.onInit();
print("onInit: 初始化");
}
@override
void onClose() {
super.onClose();
print("onClose: 销毁");
}
}
生命周期管理
GetX 会根据对象的使用情况自动释放 Controller(默认在路由销毁时释放)。
可以设置:
// permanent: true → 永久存活,直到手动删除。
Get.put(CountController(), permanent: true);
flowchart TD A[创建控制器
Controller] --> B{"注入方式"} B -->|"Get.put()" | C["立即创建
并存入容器"] B -->|"Get.lazyPut()" | D["懒加载
第一次使用时创建"] B -->|"Get.putAsync()" | E["异步创建
等待初始化完成"] B -->|"Get.create()" | F["每次 Get.find()
都创建新实例"] C --> G["GetX 容器
(全局存储依赖)"] D --> G E --> G F --> G G --> H["Get.find()
获取依赖对象"] H --> I{"生命周期管理"} I -->|"默认" | J["随路由销毁自动释放"] I -->|"permanent: true" | K["永久存活
需手动删除"] I -->|"手动" | L["Get.delete()
删除依赖"] I -->|"全部" | M["Get.reset()
清空容器"]