Dagger2 - Unbelievable, but I love you so much

Dagger2 - Unbelievable, but I love you so much

Creation

Today we are going to talk about a slightly less popular library called Dagger. I will make an irresponsible guess: those who work on the client side may rarely hear some terms, such as aspect-oriented programming, inversion of control, and dependency injection. I believe that those who have used Spring will definitely know these things that are confusing at first but very fun later.

Today we will introduce this dependency injector - Dagger2, which is derived from Square's Dagger and developed by Google. It is a dependency injection tool based on apt to generate static compilation time. It has higher performance than dynamic injection, but requires more conventions.

Official website: https://google.github.io/dagger/

composition

Dagger2 (hereinafter referred to as Dagger) is mainly composed of two parts: Component and Module. They exist in the entire dependency graph as injectors and injection sources respectively. Then, with the source and the tool, we only need to add the @Inject annotation where we need to inject. It is part of JSR-330. Here we directly introduce a simplest Demo.

Module

  1. @Module
  2. public class AppModule {
  3. Context mApplicationContext;
  4.  
  5. public AppModule(Context context) {
  6. this.mApplicationContext = context;
  7. }
  8.  
  9. @Provides
  10. public Context provideContext(){
  11. return mApplicationContext;
  12. }
  13.  
  14. @Provides
  15. public Service provideService(Context context) {
  16. return new Service(context, null );
  17. }
  18. }

This is the origin of the world.

  • The @Module annotation indicates that this class is a Module and a "source".
  • The @Provides annotation tells Dagger that we want to construct the object and provide these dependencies.

Component

  1. @Component(modules=AppModule.class)
  2. public interface AppComponent {
  3. void inject(App app);
  4.  
  5. Context context();
  6. Service service();
  7. }

Component is an interface, and the specific implementation is generated for you by Dagger through the apt tool (isn't it great to have apt?). We specify the potion - AppModule for the "needle" of AppComponent, telling it to get the variable instance we want from AppModule when injecting. As long as we declare a method with no return value and a parameter of the injected type for Component, Dagger will generate a MemberInjector object for this class to inject objects into the injected class.

Injected object

  1. public class App extends Application {
  2.  
  3. @Inject Service mService;
  4.      
  5. private AppComponent mAppComponent;
  6.  
  7. /**
  8. * Application initialization
  9. */
  10. @Override
  11. public void onCreate() {
  12. super.onCreate();
  13. mAppComponent = DaggerAppComponent.builder()
  14. .appModule(new AppModule(this))
  15. .build();
  16.  
  17. mAppComponent.inject(this);
  18.  
  19. }
  20.      
  21. public AppComponent getAppComponent() {
  22. return mAppComponent;
  23. }
  24. }

The DaggerAppComponent here is generated by Dagger. Its implementation class will add a Dagger prefix before all Component interface classes. We only need to pass in the dependencies it needs. Component obviously depends on Module, so we need to pass in AppModule here. Now, we can get this AppComponent instance wherever Context is used. As long as we have this instance, we can inject the managed class anywhere.

Scope

When we talk about dependency injection, scope is a word that often comes to our mind. Controlling the life cycle of a variable is actually controlling the scope in which it exists. Typical scopes on the server side include Singleton, Request, Session, etc. Their variables exist in different life cycles.

The default is Singleton, which is the @Singleton annotation. Objects generated by the provider annotated with it will be cached and wrapped with SingleCheck or DoubleCheck. The scope specified by our provider needs to be consistent with the scope of the component.

For example, Component is defined like this:

  1. @Singleton
  2. @Component(modules=AppModule.class)
  3. public interface AppComponent {
  4. void inject(App app);
  5.  
  6. Service service();
  7. }

And the Module looks like this

  1. @Module
  2. public class AppModule {
  3. Context mApplicationContext;
  4.  
  5. public AppModule(Context context) {
  6. this.mApplicationContext = context;
  7. }
  8.  
  9. @Singleton
  10. @Provides
  11. public Context provideService(){
  12. return new Service();
  13. }
  14.  
  15. }

Qualifiers

Dagger also supports the use of qualifiers to specify injected objects, such as the built-in @Named qualifier. When we need a variable with a specific qualified name, we can specify the @Named qualifier on @Inject to get the specified object.

  1. //Module
  2. @Providers
  3. @Named( "cache" )
  4. public Service provideService();
  5.  
  6. // Injection
  7. @Inject
  8. @Named( "cache" )
  9. Service mService;

This will inject an instance named "cache" into the mService.

A simple scenario application

What do we talk about when we talk about dependency injection?

Actually, we are discussing scope.

What does this mean? I believe it is very simple for every programmer to implement a singleton, just makeInstance and getInstance. But have you ever thought about maintaining "double instances"? I have encountered a scenario as follows:

  1. User (User) requires a tag table, which can be added, deleted, checked and modified, and is associated with the user.
  2. Questions also require a tag table, which can be added, deleted, checked, and modified, and associated with questions.
  3. The entity models of these two tables are exactly the same.

Then we have two solutions, dual tables or dual databases. Dual tables are not friendly to ORM, because ORM determines the table based on the class. In order to make the code concise and elegant, we cannot create two identical classes, otherwise naming becomes a difficult task. Here, one advantage is that the ORM library I use first maintains a singleton, which performs CRUD operations, and a singleton is related to a database. So I used the characteristics of Qualifer to generate two instances (that is, corresponding to two databases), and injected them into different business models respectively. They can use the same class, and it has no effect on the modification of the tag. If we do this ourselves, we may have to write a lot of dirty code, but Dagger solves my needs with only 2 annotations.

Summarize

Well, this article briefly explains how to get started with Dagger. In summary, as long as we agree on Component and Module and use them with Inject, we can implement a static dependency injection process. Next time we will introduce the code structure generated by Dagger in detail.

<<:  Android Custom View

>>:  How long will it take for VR to enter its spring?

Recommend

2021 Teacher Xiaofei's Stock Theory Practical Training Camp 14th

1. This "Tip Chan Theory Practical Training ...

How to use soft articles to create word-of-mouth marketing?

Word-of-mouth marketing is a widely used promotio...

[Photo] iPhone 7/7 Plus performance review: crushing Android flagships

[[173106]] In this evaluation, AnandTech still us...

Microsoft is smart to embrace Android and iOS

[[134845]] Since the new Microsoft CEO Satya Nade...

A new perspective on the four winning marketing rules

To design a successful home delivery activity pla...

How to plan a complete online event? Here is a complete plan

Why is it that with the same budget, the final re...