likes
comments
collection
share

Flutter之GetX依赖注入使用详解

作者站长头像
站长
· 阅读数 1

前面用两篇文章介绍了 GetX 的使用和通过源码剖析了 GetX 依赖注入实现原理:

了解 GetX 依赖注入原理后,本篇文章将通过不同的注入方法和参数设置详细介绍 GetX 依赖注入的使用。

put

为了验证依赖注入的功能,首先创建两个测试页面:PageA 和 PageB ,PageA 添加两个按钮 toBfind ,分别为跳转 PageB 和获取依赖;在 PageB 中通过 put 方法注入依赖对象,然后调用按钮触发 find 获取依赖。关键源码如下:

PageA

TextButton(
  child: const Text("toB"),
  onPressed: (){
      /// Navigator.push(context, MaterialPageRoute(builder: (context) => const PageB()));
      /// Get.to(const PageB());
  },
),

TextButton(
  child: const Text("find"),
  onPressed: () async {
    User user = Get.find();
    print("page a username : ${user.name}  id: ${user.id}");
  })

PageB:

Get.put(User.create("张三", DateTime.now().millisecondsSinceEpoch)));

User user = Get.find();

TextButton(
  child: const Text("find"),
  onPressed: (){
    User user = Get.find();
    print("${DateTime.now()} page b username : ${user.name}  id: ${user.id}");
  })

其中 User 为自定义对象,用于测试注入,源码如下:

User:

class User{
  final String? name;
  final int? id;
  
  factory User.create(String name, int id){
    print("${DateTime.now()} create User");
    return User(name, id);
  }
}

Navigator 路由跳转

首先使用 Flutter 自带的路由管理从 PageA 跳转 PageB, 然后返回 PageA 再点击 find 按钮获取 User 依赖:

Navigator.push(context, MaterialPageRoute(builder: (context) => const PageB()));

流程:PageA -> PageB -> put -> find -> PageA -> find

输出结果:

/// put
I/flutter (31878): 2022-01-27 19:18:20.851800 create User
[GETX] Instance "User" has been created

/// page b find  
I/flutter (31878): 2022-01-27 19:18:22.170133 page b username : 张三  id: 1643282300139
 
/// page a find 
I/flutter (31878): 2022-01-27 19:18:25.554667 page a username : 张三  id: 1643282300139

GetX 路由跳转

接下来换成使用 GetX 进行路由跳转进行同样的操作,再看看输出结果:

Get.to(const PageB());

流程:PageA -> PageB -> put -> find -> PageA -> find

输出结果:

[GETX] GOING TO ROUTE /PageB

/// put
I/flutter (31878): 2022-01-27 19:16:32.014530 create User
[GETX] Instance "User" has been created

/// page b find
I/flutter (31878): 2022-01-27 19:16:34.043144 page b username : 张三  id: 1643282192014
[GETX] CLOSE TO ROUTE /PageB
[GETX] "User" deleted from memory

/// page a find error
E/flutter (31878): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: "User" not found. You need to call "Get.put(User())" or "Get.lazyPut(()=>User())"

发现在 PageB 中获取是正常,关闭 PageB 时输出了一句 "User" deleted from memory 即在 PageB 注入的 User 被删除了,此时在 PageA 再通过 find 获取 User 就报错了,提示需要先调用 put 或者 lazyPut 先注入依赖对象。这就验证了使用 GetX 路由跳转时,使用 put 默认注入依赖时,当页面销毁依赖也会被回收。

permanent

关键代码:

Get.put(User.create("张三", DateTime.now().millisecondsSinceEpoch), permanent: true);

流程:PageA -> PageB -> put -> find -> PageA -> find

输出结果:

[GETX] GOING TO ROUTE /PageB
/// put
I/flutter (31878): 2022-01-27 19:15:16.110403 create User
[GETX] Instance "User" has been created

/// page b find  
I/flutter (31878): 2022-01-27 19:15:18.667360 page b username : 张三  id: 1643282116109
[GETX] CLOSE TO ROUTE /PageB
[GETX] "User" has been marked as permanent, SmartManagement is not authorized to delete it.

/// page a find success
I/flutter (31878): page a username : 张三  id: 1643282116109

设置 permanent 为 true 后,返回 PageA 同样能获取到依赖对象,说明依赖并没有因为页面销毁而回收,GetX 的日志输出也说明了 User 被标记为 permanent 而不会被删除:"User" has been marked as permanent, SmartManagement is not authorized to delete it.

lazyPut

lazyPut 为延迟初始化依赖对象 :

Get.lazyPut(() => User.create("张三", DateTime.now().millisecondsSinceEpoch));

TextButton(  
    child: const Text("find"),  
    onPressed: () async {    
        User user = Get.find();    
        print("${DateTime.now()} page b username : ${user.name}  id: ${user.id}"); 
      })

流程:PageA -> PageB -> put -> find -> find -> PageA -> find, 从 PageA 跳转 PageB,先通过 lazyPut 注入依赖,然后点击 find 获取依赖,过 3 秒再点击一次,然后返回 PageA 点击 find 获取一次。

输出结果:

[GETX] GOING TO ROUTE /PageB
/// lazyPut  

/// page b find 1
I/flutter (31878): 2022-01-27 17:38:49.590295 create User
[GETX] Instance "User" has been created
I/flutter (31878): 2022-01-27 17:38:49.603063 page b username : 张三  id: 1643276329589

/// page b find 2  
I/flutter (31878): 2022-01-27 17:38:52.297049 page b username : 张三  id: 1643276329589
[GETX] CLOSE TO ROUTE /PageB
[GETX] "User" deleted from memory

/// page a find error
E/flutter (31878): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: "User" not found. You need to call "Get.put(User())" or "Get.lazyPut(()=>User())"

通过日志发现 User 对象是在第一次调用 find 时进行初始化话的,第二次 find 时不会再次初始化 User;同样的 PageB 销毁时依赖也会被回收,导致在 PageA 中获取会报错。

fenix

lazyPut 还有一个 fenix 参数默认为 false,作用是当销毁时,会将依赖移除,但是下次 find 时又会重新创建依赖对象。

lazyPut 添加 fenix 参数 :

 Get.lazyPut(() => User.create("张三", DateTime.now().millisecondsSinceEpoch), fenix: true);

流程:PageA -> PageB -> put -> find -> find -> PageA -> find,与上面流程一致。

输出结果:

[GETX] GOING TO ROUTE /PageB
/// lazyPut
  
/// page b find 1
[GETX] Instance "User" has been created
I/flutter (31878): 2022-01-27 17:58:58.321564 create User
I/flutter (31878): 2022-01-27 17:58:58.333369 page b username : 张三  id: 1643277538321

/// page b find 2 
I/flutter (31878): 2022-01-27 17:59:01.647629 page b username : 张三  id: 1643277538321
[GETX] CLOSE TO ROUTE /PageB

/// page a find success
I/flutter (31878): 2022-01-27 17:59:07.666929 create User
[GETX] Instance "User" has been created
I/flutter (31878): page a username : 张三  id: 1643277547666

通过输出日志分析,在 PageB 中的表现与不加 fenix 表现一致,但是返回 PageA 后获取依赖并没有报错,而是重新创建了依赖对象。这就是 fenix 的作用。

putAsync

putAsyncput 基本一致,不同的是传入依赖可以异步初始化。测试代码修改如下:

print("${DateTime.now()} : page b putAsync User");
Get.putAsync(() async {
  await Future.delayed(const Duration(seconds: 3));
  return User.create("张三", DateTime.now().millisecondsSinceEpoch);
});

使用 Future.delayed 模拟耗时操作。

流程:PageA -> PageB -> put -> find -> PageA -> find

输出结果:

[GETX] GOING TO ROUTE /PageB

/// putAsync 
I/flutter (31878): 2022-01-27 18:48:34.280337 : page b putAsync User
 
/// create user
I/flutter (31878): 2022-01-27 18:48:37.306073 create User
[GETX] Instance "User" has been created
 
/// page b find
I/flutter (31878): 2022-01-27 18:48:40.264854 page b username : 张三  id: 1643280517305
[GETX] CLOSE TO ROUTE /PageB
[GETX] "User" deleted from memory

/// page a find error
E/flutter (31878): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: "User" not found. You need to call "Get.put(User())" or "Get.lazyPut(()=>User())"

通过日志发现,put 后确实是过了 3s 才创建 User。

create

Get.create(() => User.create("张三", DateTime.now().millisecondsSinceEpoch));

流程:PageA -> PageB -> put -> find -> find -> PageA -> find

输出结果:

[GETX] GOING TO ROUTE /PageB
/// create 
  
/// page b find 1
I/flutter (31878): 2022-01-27 18:56:10.520961 create User
I/flutter (31878): 2022-01-27 18:56:10.532465 page b username : 张三  id: 1643280970520

/// page b find 2
I/flutter (31878): 2022-01-27 18:56:18.933750 create User
I/flutter (31878): 2022-01-27 18:56:18.934188 page b username : 张三  id: 1643280978933
  
[GETX] CLOSE TO ROUTE /PageB

/// page a find success
I/flutter (31878): 2022-01-27 18:56:25.319224 create User
I/flutter (31878): page a username : 张三  id: 1643280985319

通过日志发现,确实是每次 find 时都会重新创建 User 对象,并且退出 PageB 后还能通过 find 获取依赖对象。

总结

通过代码调用不同的注入方法,设置不同的参数,分析输出日志,详细的介绍了 putlazyPutputAsynccreate 以及 permanentfenix 参数的具体作用,开发中可根据实际业务场景灵活使用不同注入方式。关于注入的 tag 参数将在后续文章中详细介绍。