first, the basic concept
Dependency Injection (DI) and inversion of Control (IOC):
Dependency injection is described from an application perspective, where dependency injection can be described as the complete point: The application relies on the container to create and inject the external resources it needs, while control inversion is described from the container's perspective, describing the complete point: container control applications, the external resources required by the container to inject the application into the application in reverse.
Using dependency injection can provide the following benefits:
Dependent injections and configurations are independent of the components.
Because objects are initialized in a separate, decoupled place, when injecting an abstract method, we only need to modify the object's implementation, rather than changing the code base.
Dependencies can be injected into a component: we can inject these dependent simulation implementations, which makes testing easier.
Second, Java and Android dependency injection
In order to maximize the reusability, testability and maintainability of code, Java Dependency Injection defines a set of annotations (and interfaces) standard Java Dependency Injection standards (jsr-330,dependency injection for Java) in the use of Injection classes 1.0 The specification was released in October 2009.
Dagger1 is the most popular dependency injection framework on Android. It was created by the square company inspired by Guice. Dagger2 is a branch of Dagger1, developed by Google, the current version is 2.2. Dagger2 is inspired by the Autovalue project
Android developed from the beginning of the MVC framework, to the MVP, to MVVM, constantly changing. Now the data-binding of MVVM is still in the experimental phase, the traditional MVC framework activity may contain a lot of code, difficult to maintain, now the mainstream architecture is the use of MVP (Model + View + Presenter) way. But the MVP framework also has the potential to centralize large amounts of code in Presenter, and Introducing DI framework Dagger2 allows decoupling between Presenter and Activity, decoupling Presenter from other business logic, and improving modularity and maintainability.
Dagger GitHub address is
Https://github.com/square/dagger
Https://github.com/google/dagger
Dagger2 's improvements to dagger are as follows
No reflection is used: the validation, configuration, and pre-setup of the diagram are performed at compile time.
Easy to debug and traceable: completely and specifically invokes the provided and created stacks
Better performance: Google claims that they have improved processing performance by 13%
Code obfuscation: Using dispatch methods, just as you write your own code
Here we only analyze the use of Dagger2 and source code, the following all dagger refers to Dagger2
third, the use of dagger1. Introduction of related libraries
Dagger Gradle is not simple in dependencies with the relevant compile can be, here to say the configuration method
dependencies { classpath ' com.android.tools.build:gradle:2.1.0 ' classpath ' com.neenbedankt.gradle.plugins : android-apt:1.4 ' } Apply plugin: ' com.neenbedankt.android-apt ' dependencies { compile filetree (dir: ' Libs ', Include: [' *.jar ']) compile group: ' Com.google.dagger ', Name: ' Dagger ', Version: ' 2.4 ' compile group: ' Com.google.dagger ', Name: ' Dagger-compiler ', Version: ' 2.4 '}
The resulting intermediate file is in Build/generated/source/apt/debug.
2. Annotations@Inject: This annotation is usually used where you need to rely. Tell Dagger that this class or field requires dependency injection. In this way, Dagger constructs an instance of this class and satisfies their dependencies.
@Module: The method in the Modules class specifically provides dependencies, so we define a class, annotated with @module, so that dagger, when constructing an instance of the class, knows where to find the required dependency. An important feature of modules is that they are designed to be partitioned and grouped together.
@Provides: In modules, the method we define is to use this annotation to tell Dagger that we want to construct the object and provide those dependencies.
@Component: Components are essentially an injector, or a bridge between @inject and @module, whose main function is to connect the two parts. Components can provide an instance of all defined types, such as: we must annotate an interface with @component and then list all the @Modules make up the component, and if any of the pieces are missing, the error will be made at compile time. All components can know the range of dependencies through its modules.
@Scope: Dagger2 can limit the scope of annotations by customizing annotations. 3. Injection-dependent
The injection dependency methods provided by Dagger are:
Construct method Injection: Comment @inject before class construction method
Member variable injection: Comment @inject in front of the member variable (non-private) of the class
Function method Injection: Comment @inject in front of the function
The above sequence is recommended by dagger because there are always some strange problems or even null pointers in the process of running, which also means that dependencies may not be initialized when the object is created.
Class Thermosiphon implements Pump { private final heater heater; @Inject Thermosiphon (heater heater) { this.heater = heater; } ...} Class Coffeemaker { @Inject heater heater; ...} Class Coffeemaker { @Inject public void Setpump (Pump Pump) { this.pump=pump; } ...}
If the member variable is annotated @Inject, but there is no annotation construction method, the required words are injected, but no new objects are created. If you annotate an parameterless constructor, you can create a new object.
Classes that do not pass @Inject annotations cannot be created with dagger.
4. Meet the dependency relationship
Interfaces cannot be constructed.
Third party classes cannot be specified.
Configuration objects must be configured
We need to implement dependencies by means that are annotated by @Provides annotations. The return type of each method is the dependency we need to implement.
Once you need to inject a heater,provideheater () it will be called:
@Provides Heater Provideheater () { return new Electricheater ();}
methods that are @Provides labeled can also have dependencies on their own.
You need Pump as a dependency to return an instance of Thermosiphon:
@Provides Pump providepump (Thermosiphon Pump) { return Pump;}
all methods of @Provides labeling must belong to a module. The class labeled with @Module is a Module.
@Moduleclass Dripcoffeemodule { @Provides heater provideheater () { return new Electricheater (); @Provides Pump providepump (Thermosiphon Pump) { return Pump; }}
By convention, the method of @Provides labeling is named by provide as a prefix, and the module class is named by the module as a suffix. 5. Build Diagram
Classes labeled with @Inject and @Provides will eventually form a graph of objects,
In Dagger2, the collection dependency is a method of an interface definition, without any parameters, returning only the desired type. By applying the @componet annotation to such an interface and passing the module type to the module parameter.
Dagger is a dependency injection library based on the dag--graph structure, and the Directed acyclic graph is used to avoid cyclic dependence in the use of dagger.
@Component (modules = Dripcoffeemodule.class) interface CoffeeShop { coffeemaker maker ();}
The implementation is based on the interface name with the dagger prefix, calling the builder method to set the dependent build instance.
CoffeeShop coffeeshop = Daggercoffeeshop.builder () . Dripcoffeemodule (New Dripcoffeemodule ()) . Build ();
If the @Component is not the outermost annotation, besides the prefix, you also need to connect the name of the external structure with _
Class Foo { static class Bar { @Component interface bazcomponent {} }}
生成的组件名称为DaggerFoo_Bar_BazComponent
有一个可访问的默认构造函数的module都可以作为构建者,如果没有设置,会自动构造一个实例。而对于@Provides方法都是静态的module,实现不需要实例。如果所有的依赖性会未经用户创建一个实例的依赖构造,则生成的实现类将具有create()方法可用于获取一个新的实例,而不必处理builder方式。
CoffeeShop coffeeshop = Daggercoffeeshop.create ();
6、单例和使用范围绑定
Using the @provides annotation method, plus @Singleton, you can guarantee the generation of a singleton. There is only one instance of the entire life cycle
Classes that use @singleton annotations can be shared in multiple threads.
The life cycle of different scopes is different, and the single singleton annotation (application scope) is the longest scope
The component may have more than one scope comment. They have the same scope of use, and different annotations are equivalent to aliases, so the component can include any binding that it declares scope-scoped. To declare a component to be associated with a given scope, simply apply the scope comment to the component interface.
@Provides @Singleton static Heater provideheater () { return new Electricheater ();}
@Singletonclass coffeemaker { ...}
@Component (modules = dripcoffeemodule.class) @Singletoninterface coffeeshop { coffeemaker maker ();}
Customizing Scope
@Scope @retention (RUNTIME) public @interface peractivity {}
@PerActivity @component (dependencies = applicationcomponent.class, modules = activitymodule.class) public interface Homecomponent extends Abstractactivitycomponent { void inject (homeactivity homeactivity); void inject (Homefragment homefragment);}
7. Reusable Use range
Sometimes it is useful to limit the number of classes instantiated by the @inject annotation to the exact same instance of the life cycle of any component or subcomponent, and the memory in Android is more precious. Classes that use @reusable annotations are cached after the object is instantiated. After the parent component is cached, subclasses are reused.
There is no guarantee that the component will call binding only once, and it is dangerous to use the @reusable binding to return objects with variable values, or to point to objects that are important to the same instance. If you do not care how many objects are created, immutable objects are not scoped, and using @reusable annotations is safe.
@Reusable//It doesn ' t matter how many scoopers we use, but don ' t waste them.class coffeescooper { @Inject Coffeescoo Per () {}} @Moduleclass cashregistermodule { @Provides @Reusable//DON ' T do this! Which register you put your cash in. Use a specific scope instead. Static Cashregister Badideacashregister () { return new Cashregister ();} } @Reusable//DON ' T do this! You really does want a new filter each time, so this //should be Unscoped.class coffeefilter { @Inject coffeefilter () {}}
8. Lazy Loading Injection
There are times when you need to lazy load, to use lazy<t>
There is only one get method, and dagger does not create an object if it is not called
After the call, create the object and save
Call again to return the same object
Class Gridingcoffeemaker { @Inject lazy<grinder> lazygrinder; public void Brew () {while (needsgrinding ()) { //Grinder created once on first call to. Get () and cached. Lazygrinder.get (). Grind ();}} }
9, using provider injection
In some cases, you need multiple object instances instead of just injecting an object instance. At this point you can use the provider implementation, each call to provider's get () function will return the new <T> object instance.
Class Bigcoffeemaker { @Inject provider<filter> filterprovider; public void Brew (int numberofpots) { ... for (int p = 0; p < numberofpots; p++) { maker.addfilter (Filterprovider.get ());//new filter every time. Maker.addcoffee (...); Maker.percolate (); ... } }}
10, the use of qualifiers
Sometimes a separate type is not sufficient to identify a differentiated dependency. You can use qualifier annotations at this time, using @named annotations here,
Class Expensivecoffeemaker { @Inject @Named ("water") heater waterheater; @Inject @Named ("Hot plate") heater hotplateheater; ...}
@Provides @Named ("Hot plate") static heater Providehotplateheater () { return new Electricheater (70);} @Provides @Named ("water") static heater Providewaterheater () { return new Electricheater (93);}
The use of this framework is relatively small, mainly reference GitHub documentation
Http://google.github.io/dagger/users-guide.html
using the MVP is less, the project is basically MVC, this framework is not very applicable. Can not give full play to dagger advantage.
This article is not very thorough. Later in-depth look at the source code, and then do detailed analysis.
Welcome to scan QR Code, pay attention to public accounts.
Android Dependency Injection dagger usage and source parsing (previous)