Android development Article 1 usage and understanding of the dependency injection framework dagger2
(This blog is really tough. I wrote about half of the computer's blue screen. Fortunately, the markdown editor maintains the category)
Recently, we started to refactor the project and used the dependency injection framework dagger2 In the refactoring project. We found that it is really convenient and can greatly speed up coding, at the same time, it is very convenient for us to decouple functional modules. Here we will not go into more about dagger2. Google Baidu will be able to get a lot of introductions about dagger2. Learning dagger2 requires a certain learning cost. It took me almost a week to learn how to use dagger2, the following describes how to understand and use dagger2.
In dagger2, the most important thing is module and component. module is the place where we need to produce objects. component is a bridge between the use scenarios of the objects produced by module and module. (To put it bluntly, dagger2 is like the factory model in the design mode, producing various objects we need for US)
Do not understand? Code on: (if we have A class A, then we need to use it in MainActivity through the dependency injection method)
No. ×××××××××× // class Apublic class A {private int field ;... // other attributes public A () {} public void doSomething () {Log. I ("beauty", "I love you");} public void doOtherthing () {Log. I ("beauty", "I really love you ");}... // other methods} // class MainActivitypublic class MainActivity extends AppCompatActivity {@ Override public void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); A a = new A ();. doSomething ();. doOtherthing ();}} ×××××××××××××××××××××××× use dagger2 ××××××××××××××××× × ××××××××× // class A public class A {private int field ;... // other attributes public A () {} public void doSomething () {Log. I ("beauty", "I love you");} public void doOtherthing () {Log. I ("beauty", "I really love you ");}... // other methods} // we need to construct A Module first. The Module produces the Object @ Modulepublic class AMedule {@ Provides A provideA () {return new A () ;}/// then A Component is required to connect the Module and MainActivity @ Component (modules = AMedule. class) public interface ActivityComponent {A a () ;}// use the public class MainActivity extends AppCompatActivity {@ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); ActivityComponent component = DaggerActivityComponent. builder (). aMedule (new AMedule ()). build (); A a = component. a ();. doSomething ();. doOtherthing ();}}
A simple dependency injection is complete. You may think this writing is very troublesome. Otherwise, there is a simpler way to do this. We Inject B into BComponent and directly use the @ Inject annotation:
// Class A public class A {private int field ;... // other attributes public A () {} public void doSomething () {Log. I ("beauty", "I love you");} public void doOtherthing () {Log. I ("beauty", "I really love you ");}... // other methods} // we must first construct A Module @ Modulepublic class AMedule {@ Provides A provideA () {return new ();}} // then a Component @ Component (modules = AMedule. class) public interface ActivityComponent {void inject (MainActivity mainActivity);} // use public class MainActivity extends AppCompatActivity {@ Inject; @ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); DaggerActivityComponent. builder (). aMedule (new AMedule ()). build (). inject (this);. doSomething ();. doOtherthing ();}}
Is it easy and convenient. What? It's still troublesome. Let's proceed further (because Class A is defined by ourselves, we can proceed further ):
// Class A public class A {private int field ;... // other attributes @ Inject public A () {} public void doSomething () {Log. I ("beauty", "I love you");} public void doOtherthing () {Log. I ("beauty", "I really love you ");}... // other methods} // we need to construct A Module first (in fact, the Module is not used here, we do not need to produce A through Modu, but to compare it with the above, keep it.) @ Modulepublic class AMedule {// @ Provides // A provideA () {// return new (); ///} // a Component @ Component (modules = AMedule. class) public interface ActivityComponent {void inject (MainActivity mainActivity);} // use public class MainActivity extends AppCompatActivity {@ Inject; @ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); DaggerActivityComponent. builder (). aMedule (new AMedule ()). build (). inject (this);. doSomething ();. doOtherthing ();}}
Is it confused? A is not produced in the Module. Why? I don't know if you have noticed that there is A @ Inject Annotation on the constructor of A. That's right. It's the annotation that produces object.
We can see that there are two ways to produce dagger2 objects. One is to add the providexxx Method to the Module through the @ Provides annotation, the other is to add the @ inject annotation directly to the construction method of the class of the object to be produced.
So when to use Module and @ Inject?
Here, we will quietly tell you that Module is generally used to generate the class objects provided by the system, SDK, or third-party libraries, while the custom class objects use @ Inject. Of course, you can also use a class to inherit the class provided by the system, SDK, or third-party library, and add the @ Inject annotation to its constructor.
2. Maybe you still seem to understand Module and Component. Here is a metaphor.
For example, when the meal time is up, we have to cook (take-out detour). We have to go to the kitchen (hopefully it's not a field barbecue). We need a gas stove (or an Induction Cooker ), pot, knife, chopping board, basin .... (Find the real Doha needed), these are all categories. The specific rice cookers in your kitchen, such as Midea (do you have to pay some advertising fees for Midea), supor (just bought one) ..... It is a specific object. With these specific objects, we can cook happily, and the Module is to let us get these objects (a large factory, producing rice cookers, supor ....), Component is our kitchen, DaggerActivityComponent. builder (). aMedule (new AMedule ()). build () is to let us have a kitchen (think about the pocket of a robot cat, we can get everything from it), we can take cooking utensils from the kitchen (take it out: A a = component. a (), this is to take the food in the kitchen outside the kitchen, cook outside), and DaggerActivityComponent. builder (). aMedule (new AMedule ()). build (). inject (this) means that we enter the kitchen and cook in the kitchen. (Of course we can easily get the cooking utensils in the kitchen. Use @ Inject to cook...
3. A Component can depend on multiple modules, such
@Component(modules = {AModule.class,BModule.class,...})
Similarly, Component can depend on another Component, such
@Component(dependencies = BComponent.class,modules = {AModule.class,BModule.class,...})
More than one Component, such
@Component(dependencies = {BComponent.class,CComponent.class,...}
,modules = {AModule.class,BModule.class,...})
Note that the dependent Component must expose the object so that the dependent Component can obtain the object, as shown in figure
// Dependent Component @ Component (modules = {...}) public interface BComponent {A a (); B B () ;}// dependent Component @ Component (dependencies = BComponent. class, modules = {...}) public interface CComponent {}
CComponent can obtain objects A and B through BComponent. Other BComponent objects are transparent to CComponent and invisible.
4. @ Scope Annotation
This annotation is used to divide the scope (where to use it), which means that I will draw an area and put all the items produced here if they are limited to this scope, the scenario class of the scope (generally the place where the object is consumed, such as the Activity). Next time I need an object, I will take it here. If so, I will use it directly. If not, put it here and use it on your own (is there a way to make it easier for yourself and others). dagger2 has an existing @ Scope annotation called @ Singleton, this is the singleton mode that everyone is familiar with. You can also customize @ Scope annotations. For example, to limit that an object produced can only be used in the Activity and can only be used in the Application, it can only be used in Fragment...
For example, we write a Scope Annotation with a limited Scope of Activity.
@Scope@Documented@Retention(RetentionPolicy.RUNTIME)public @interface PerActivity {}
Usage (constructor Mode)
// Class A @ PerActivity public class A {private int field ;... // other attributes @ Inject public A () {} public void doSomething () {Log. I ("beauty", "I love you");} public void doOtherthing () {Log. I ("beauty", "I really love you ");}... // other methods} // then a Component @ PerActivity @ Component () public interface ActivityComponent {void inject (MainActivity mainActivity );} // use the public class MainActivity extends AppCompatActivity {@ Inject A a; @ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); DaggerActivityComponent. builder (). build (). inject (this);. doSomething ();. doOtherthing ();}}
Usage (Module Mode)
// Class A public class A {private int field ;... // other attributes public A () {} public void doSomething () {Log. I ("beauty", "I love you");} public void doOtherthing () {Log. I ("beauty", "I really love you ");}... // other methods} // we must first construct A Module @ Modulepublic class AMedule {@ PerActivity @ Provides A provideA () {return new ();}} // then a Component @ PerActivity @ Component (modules = AMedule. class) public interface ActivityComponent {void inject (MainActivity mainActivity);} // use public class MainActivity extends AppCompatActivity {@ Inject; @ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); DaggerActivityComponent. builder (). aMedule (new AMedule ()). build (). inject (this);. doSomething ();. doOtherthing ();}}
Didn't you understand? Okay, let's continue.
If we have another SecondActivity, we also need to use the object.
// Class A public class A {private int field ;... // other attributes public A () {} public void doSomething () {Log. I ("beauty", "I love you");} public void doOtherthing () {Log. I ("beauty", "I really love you ");}... // other methods} // we must first construct A Module @ Modulepublic class AMedule {@ PerActivity @ Provides A provideA () {return new ();}} // then a Component @ PerActivity @ Component (modules = AMedule. class) public interface ActivityComponent {void inject (MainActivity mainActivity); void inject (SecondActivity secondActivity);} // use public class MainActivity extends AppCompatActivity {@ Inject; @ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); DaggerActivityComponent. builder (). aMedule (new AMedule ()). build (). inject (this);. doSomething ();. doOtherthing () ;}}// use public class SecondActivity extends AppCompatActivity {@ Inject A; @ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); DaggerActivityComponent. builder (). aMedule (new AMedule ()). build (). inject (this);. doSomething ();. doOtherthing ();}}
Here, the object A of MainActivity and SecondActivity is the same
5. sub-Component
The sub-Component depends on another Component. The difference is that the sub-Component can obtain all the objects that can be produced by the parent Component, the Component dependency can only obtain the production objects exposed by the dependent Component.
Example:
// Class A public class A {private int field ;... // other attributes public A () {} public void doSomething () {Log. I ("beauty", "I love you");} public void doOtherthing () {Log. I ("beauty", "I really love you ");}... // other methods} // we must first construct A Module @ Modulepublic class AMedule {@ Provides A provideA () {return new ();}} // then a Component @ Component (modules = AMedule. class) public interface ActivityComponent {void inject (MainActivity mainActivity); void inject (SecondActivity secondActivity);} // then a Component @ Component (modules = AMedule. class) public interface BComponent {void inject (MainActivity mainActivity); CComponent plus (Module1 module1, Module2 module2 ,...); // The parameter is CComponent dependent Module} // then a sub-Component (using the @ Subcomponent annotation) @ Subcomponent (modules = {...}) public interface CComponent {void inject (SecondActivity secondActivity);} // used in the MainActivity class, injecting MainActivity into the parent Component public class MainActivity extends AppCompatActivity {@ Inject A; @ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); DaggerActivityComponent. builder (). aMedule (new AMedule ()). build (). inject (this);. doSomething ();. doOtherthing () ;}// used in the SecondActivity class to Inject SecondActivity into the sub-Component public class SecondActivity extends AppCompatActivity {@ Inject; @ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); DaggerActivityComponent. builder (). aMedule (new AMedule ()). build (). plus (new Module1 (), new Module2 (),...). inject (this);. doSomething ();. doOtherthing ();}}
6. @ Named Annotation
This annotation is used to set aliases to distinguish different objects of the same type. For example, we all know that there are two types of Context in Android: Global and Activity. To distinguish them, we can add aliases. For example, there is a Person class, he has two instances: Xiao Li and Xiao Mei. We can also use aliases to differentiate them.
// Person class public class Person {private String name; private int age; public Person () {} public Person (String name, int age) {this. name = name; this. age = age;} public String getName () {return name;} public void setName (String name) {this. name = name;} public int getAge () {return age;} public void setAge (int age) {this. age = age ;}@ Override public String toString () {return "Person {" + "name = '" + name +' \ ''+ ", age = "+ age + '}';} // we need to construct a Module @ Modulepublic class ActivityMedule {@ Named (" Xiao Li ") @ Provides Person providePerson () {return new Person ("Xiao Li", 18) ;}@ Named ("Xiao Mei") @ Provides Person providePerson () {return new Person ("Xiao Mei", 24 );}} // then a Component @ Component (modules = ActivityMedule. class) public interface ActivityComponent {void inject (MainActivity mainActivity);} // use the public class MainActivity extends AppCompatActivity {@ Named ("Xiao Li") @ Inject Person p1 in the MainActivity class; @ Named ("Xiaomei") @ Inject Person p2; @ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); DaggerActivityComponent. builder (). activityMedule (new ActivityMedule ()). build (). inject (this); Log. I ("person", p1.toString (); Log. I ("person", p2.toString ());}}
Of course, if you think that @ Named annotation cannot meet your needs, you can also use @ Qualifier to customize your own alias annotation.
7. Use of android studio
Add dependency libraries in build. gradle
compile 'com.google.dagger:dagger:2.2' compile 'com.google.dagger:dagger-compiler:2.2' provided 'org.glassfish:javax.annotation:10.0-b28'
Well, let's talk about that much!