Dagger:Dagger是Java和Android的编译时依赖注入框架。
依赖注入:依赖注入是面向对象编程的一种设计模式,其目的是为了降低程序耦合,这个耦合就是类之间的依赖引起的.
举个栗子:
public class ClassA{
private ClassB b
public ClassA(ClassB b){
this.b = b }
}
这里ClassA的构造函数里传了一个参数ClassB,随着后续业务增加也许又需要传入ClassC,ClassD.试想一下如果一个工程中有5个文件使用了ClassA那是不是要改5个文件?
这既不符合开闭原则, 也太不软工了.这个时候大杀器Dagger2就该出场了.
public class ClassA{
@inject
private ClassB b
public ClassA(){
}
}
通过注解的方式将ClassB b注入到ClassA中, 可以灵活配置ClassA的属性而不影响其他文件对ClassA的使用.
环境配置(Android Studio)
首先打开project的Gradle添加
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
再打开 app module 的 build.gradle,添加
compile 'com.google.dagger:dagger:2.4'
apt 'com.google.dagger:dagger-compiler:2.4'
compile 'org.glassfish:javax.annotation:10.0-b28'
然后sync gradle一下,环境就配置好了,在实用dagger2的时候,会自动生成一些类,所以最好记一下 build project的快捷键 ctrl+F9,写好dagger代码,然后build一下,就会自动生成 DaggerXXX 开头的一些类
入门开始:
现在有一个Person类
public class Person {
public Person() {
System.out.println("a person created");
}
}
public class MainActivity extends AppCompatActivity {
Person person;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
person = new Person();
}
}
如果不适用依赖注入,那么我们只能在MainActivity中自己new一个Person对象,然后使用。
使用依赖注入:
public class MainActivity extends AppCompatActivity {
@Inject
Person person;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
在Person对象上添加一个 @Inject
注解,即可自动注入对象。
那么问题来了,就一个@Inject
注解,系统就会自动给我创建一个对象? 当然不是,这个时候我们需要一个Person类的提供者。估计叫它: MainModule
@Module
public class MainModule {
@Provides
Person providesPerson() {
System.out.println("a person created from MainModule");
return new Person();
}
}
//无参数
private String color;
public AppleModule(String color){
this.color = color;
}
@Provides
public String providesAppleColor(){
return color;
}
DaggerAppleComponent.builder().appleModule(new AppleModule("红色")).build().inject(this);
里面两个注解,@Module
和 @Provides
,Module标注的对象,你可以把它想象成一个工厂,可以向外提供一些类的对象。那么到底提供什么对象呢?
@Provides
标注的方法就是提供对象的,这种方法一般会返回一个对象实例,例如上面返回一个 Person对象
那么好了,现在Perso类的提供者也有了,我们是不是可以运行起来了。ctrol+F9
build一下项目,然后运行。发现没有任何输出(如果创建Person对象,会打印消息)。为什么了?
这个时候需要引入第3个东东,component容器。可以把它想成一个容器, module中产出的东西都放在里面,然后将component与我要注入的MainActivity做关联,MainActivity中需要的person就可以冲 component中去去取出来。
MainComponent.java
@Component(modules = {MainModule.class})
public interface MainComponent {
void inject(MainActivity mainActivity);
}
看到一个新注入 @Component 表示这个接口是一个容器,并且与 MainModule.class 关联,它生产的东西都在这里。void inject(MainActivity mainActivity);
表示我怎么和要注入的类关联。这个比较抽象!这个时候我们可以 build 一下项目。
然后在MainActivity中将component 关联进去:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MainComponent component = DaggerMainComponent.builder()
.mainModule(new MainModule()).build();
component.inject(this);
}
下面就是将 MainActivity和Module通过Component关联起来的代码,那么这个时候系统看到 有一个 @Inject
修饰的Person,就知道在这个 MainComponent中去找,并且是有 MainModule 的 Provides修饰的方法提供的。
MainComponent component = DaggerMainComponent.builder()
.mainModule(new MainModule()).build();
component.inject(this);
然后 build 项目,运行项目,发现打印:
person from module
a person created
说明确实系统创建了对象,并且注入到MainActivity中。
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface Type {
String value() default "";
}
@Module
public class AppleModule {
@Provides
@Type("normal")
public Apple providesApple(){
return new Apple();
}
@Provides
@Type("color")
public Apple providesColorApple(){
return new Apple("红");
}
}
DaggerAppleComponent.create().inject(this);