Flutter all-rounder GetX - dependency management

 

 Use 

 Principles

1. Introduction to Dependency Injection


What it is: Originally accepting various parameters to construct an object, now it only accepts one parameter - the object that has been instantiated.
Purpose: Dependency injection is to separate the configuration of dependent components from him, so as to reduce the coupling between users and dependencies.
Implementing dependency injection gives you the following advantages:

  • Reusing code makes it easier to swap out implementations of dependencies. Code reuse is improved due to inversion of control, and classes no longer control how their dependencies are created, but support any configuration.
  • It is easy to refactor the separation of creation of dependencies, which can be checked and modified when creating objects or when compiling, and one modification is not required at the use.
  • The easily testable class doesn't manage its dependencies, so when testing, you can pass in different implementations to test all the different use cases.

 
2. The way of GetX dependency injection

  There are four ways of GetX dependency injection:

1、 put 

Most of the time we use put, which has been injected into the memory when calling, and returns a singleton by default. If you want to return a different instance object, you can set the tag parameter.

  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}");

 
 

 You can see that if you add different tags to put, it will return different instance objects. There is also a parameter of put

permanent, for objects that need to survive for a long time, you can set it to true, otherwise it is generally false.

2、lazyPut 

 This is lazy loading, which means that a dependent object will be injected only when you find it. In computationally expensive classes or

You don't know when this class will be used, and if you want to instantiate several classes in one place (such as in the Bindings class), you can use this method.

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);

Asynchronous version of Get.put(). Waits for the Future from the builder() argument to resolve and stores the returned instance.

Generally used like this:

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);

Using this method means that every time you find, a new instance object will be created, which is different from the above Get.put. It also registers each `instance.onClose()` with the current route `GetConfig.currentRoute` to keep the lifecycle alive. Be aware that the instance created just stores each route. So if you call `Get.delete<T>()`, the "instance factory" (`Get.create<T>()`) used in this method will be deleted, but not the ones already created by it instance. This means that your route must use the Get route, and the created object will be bound to the cycle of the current widget. When the widget is disposed, the instance object will be recycled. If you use native routing instance object will not be recycled.

  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

          

3. Usage of Bindings

Before using the Bindings class, I had to manually implement dependency injection in the widget. So there is still no decoupling between widget classes and dependencies. So there is the Bindings class, which can fully integrate routing, state managers and dependency managers.

Bindings can be used in two ways

1. Directly create a new class to inherit the Bindings class, then implement the dependencies method, and put the instance object to be injected.

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

The subclass of Binding should be able to write Get.to(()=>TestPage,binding:TestBinding()) when routing jumps.

 If you are using named routes, you can write:

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

2. The second way is to use BindingsBuilder. If you don’t want to create a new Bindings class every time, you can write like this

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

Also, it can also be written in GetMaterialApp. This also defines a binding parameter called initialBinding. This is the same as above. The difference is that there is no need to bind to the page.

GetX removes unused controllers from memory by default. But if you want to change how the GetX control class is destroyed, you can SmartManagementset different behaviors with the class.

  • SmartManagement.full This is the default. Destroy classes that are not used and not made permanent. In most cases we use this and no changes are required.

  • SmartManagement.onlyBuilders With this option, only init:controllers launched in or Get.lazyPut()loaded into Binding will be destroyed.

    If you use Get.put() or Get.putAsync() or any other method, SmartManagement has no permission and cannot remove this dependency.

  • SmartManagement.keepFactory is like SmartManagement.full, it will remove it's dependencies when it is no longer used, but it will keep their factory, which means if the instance is needed again, it will recreate that dependency .

Four. Summary

There are four ways for dependency injection, and we need to use the corresponding method according to different business scenarios. For Bindings, you can use them according to your own coding style. If it is useful to you, welcome to like and follow!

Guess you like

Origin blog.csdn.net/hjjdehao/article/details/126119363