Flutter 全能型选手GetX —— 依赖管理

 

 使用篇 

 原理篇

一、 依赖注入的介绍


是什么:本来接受各种参数来构造一个对象,现在只接受一个参数——已经实例化的对象。
目的:依赖注入是为了将依赖组件的配置和使他分离开,来降低使用者与依赖之间的耦合度。
实现依赖项注入可为您带来以下优势:

  • 重用代码 更容易换掉依赖项的实现。由于控制反转,代码重用得以改进,并且类不再控制其依赖项的创建方式,而是支持任何配置。
  • 易于重构 依赖项的创建分离,可以在创建对象时或编译时进行检查、修改,一处修改,使用处不需修改。
  • 易于测试 类不管理其依赖项,因此在测试时,您可以传入不同的实现以测试所有不同用例。

 
二、GetX依赖注入的方式

  GetX依赖注入有四种方式:

1、 put 

我们大部分时候使用的就是put,在调用的时候已经注入到内存中了,而且默认返回的是一个单例。如果想返回不同的实例对象,可以设置tag参数。

  S put<S>(
          // [dependency]  被注入的对象,S 表示可以是 任何类型的
          S dependency,
          {
           // [tag] 可选地,使用 [tag] 作为“id”来创建相同类型的多个记录,
           // [tag] 不会与其 他依赖项类型使用的相同标签冲突 
           String? tag,
           // 将 Instance 保存在内存中并将其持久化,而不遵循 `Get.smartManagement` 规则。
           // 虽然,可以通过 `GetInstance.reset()` 和 `Get.delete()` 删除
           bool permanent = false,
           // 可选:允许你使用函数而不是依赖(dependency)本身来创建依赖。
          InstanceBuilderCallback<S>? builder
          }) =>
      GetInstance().put<S>(dependency, tag: tag, permanent: permanent);
  Get.put(User(), tag: "user");
  Get.put(User(), tag: "user1");
  User user = Get.find(tag: "user");
  User user1 = Get.find(tag: "user1");
  print("Get.put 获取的对象比较 ${user == user1}");

 
 

 可以看到给put加上不同的tag的话,它返回的就是不同的实例对象了。还有就是put的一个参数

permanent ,对于需要对象存活较久的,就可以设置为true,不然的话一般为false就行了。

2、lazyPut 

 这个是懒加载意思是只有当你find的时候,才会注入一个依赖对象。在计算比较高昂的类或者

你不知道这个类什么时候用, 还有就是你想在一个地方实例化几个类(比如在Bindings类中),就可以使用这个方法。

lazyPut<S>(
    //当你的类第一次被调用时,将被执行的方法。
    InstanceBuilderCallback<S> builder,
      {
    //当不想让同一个类有多个不同的实例时,就会用到它,必须是唯一的
     String? tag,

     //下次使用的时候是否重建,设为true的时候,当不使用的时候,实例就会被删除,再次find的时候就会重新创建实例
     //就像 bindings api 中的 "SmartManagement.keepFactory "一样。
     bool fenix = false}
)

3、  putAsync

  Future<S> putAsync<S>(AsyncInstanceBuilderCallback<S> builder,
          {String? tag, bool permanent = false}) async =>
      GetInstance().putAsync<S>(builder, tag: tag, permanent: permanent);

Get.put() 的异步版本。等待来自 builder()参数的 Future 解析并存储返回的 实例。

一般这样使用:

Get.putAsync<SharedPreferences>(() async {
  final prefs = await SharedPreferences.getInstance();
  return prefs;
});
 

4、 create
 

void create<S>(InstanceBuilderCallback<S> builder,
          {String? tag, bool permanent = true}) =>
      GetInstance().create<S>(builder, tag: tag, permanent: permanent);

使用这个方法,表示你每次find的时候,都会创建一个新的实例对象,跟上面Get.put是有所区别的。它还将每个 `instance.onClose()` 注册到当前的路由 `GetConfig.currentRoute` ,以保持生命周期处于活动状态。要知道创建的实例仅存储每个路由。因此,如果您调用 `Get.delete<T>()`,此方法中使用的“实例工厂”(`Get.create<T>()`)将被删除,但不会删除已由它创建的实例。意思就是说, 你的路由必须要使用Get的路由,创建的对象会和当前widget的周期绑定,当widget被dispose的时候,这个实例对象就会被回收。如果使用原生路由实例对象是不会被回收的。

  Get.create(() => User());
   //Get.put(User());
  User user = Get.find();
  User user1 = Get.find();
  print("Get.create 获取的对象比较 ${user == user1}");  false
   // print("Get.put 获取的对象比较 ${user == user1}"); true

          

三、Bindings的用法

在没有使用Bindings类之前,我都是要在widget里面去手动实现依赖注入的。所以说widget类和依赖还存在没有解耦的情况。因此就有了Bindings类的出现,这个类可以将路由、状态管理器和依赖管理器完全集成。

bindings有两种使用方式

1、直接新建一个类继承Bindings类,然后实现dependencies方法,放进要注入的实例对象就行了。

class TestBinding extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut(() => TestController());
  }
}

Binding的子类要可以在路由跳转的时候这样写 Get.to(()=>TestPage,binding:TestBinding())。

 如果你使用的是命名路由的话,你可以这样写:

 GetPage(
        name: test,
        page: () => TestPage(),
        binding: TestBinding())

2、第二种方式就是使用BindingsBuilder ,如果你不想每次都新建一个Bindings类的话,你可以这样写

 GetPage(
        name: test,
        page: () => TestPage(),
        binding: BindingsBuilder(() => [Get.lazyPut(() => TestController())]))

还有就是也可以写在 GetMaterialApp里面。这个里面也定义了一个binding参数,叫initialBinding。这个跟上面的用法是一样的。不同的是,不需要跟页面进行绑定。

GetX 默认情况下会将未使用的控制器从内存中移除。 但是如果你想改变GetX控制类的销毁方式,你可以用SmartManagement类设置不同的行为。

  • SmartManagement.full 这是默认的。销毁那些没有被使用的、没有被设置为永久的类。在大多数情况下,我们都使用这个,不需要更改。

  • SmartManagement.onlyBuilders 使用该选项,只有在init:中启动的控制器或用Get.lazyPut()加载到Binding中的控制器才会被销毁。

    如果使用Get.put()或Get.putAsync()或任何其他方法,SmartManagement 没有权限也就是不能移除这个依赖。

  • SmartManagement.keepFactory 就像SmartManagement.full一样,当它不再被使用时,它将删除它的依赖关系,但它将保留它们的工厂,这意味着如果再次需要该实例,它将重新创建该依赖关系。

四、总结

对于依赖注入有四种方式,我们要根据不同的业务场景来使用相应的方法就可以了。对于Bindings,可以根据自己的编码风格来使用。如果对你有用话,欢迎点赞关注!

猜你喜欢

转载自blog.csdn.net/hjjdehao/article/details/126119363