什么是Dagger2?
Dagger2是一个依赖注入框架,那么何为依赖注入呢?依赖注入是面向对象编程的一种设计模式,其目的是为了降低程序耦合,这个耦合就是类之间的依赖引起的。
很多人说Dagger是脱裤子放屁,实际上是他们对Dagger的作用产生了误解,Dagger的作用是管理对象之间的依赖关系,从而降低耦合,而不是为了构建一个对象,是否使用Dagger的一个标准是看两个类之间的关系是依赖关系,还是组合或者聚合的关系。
举个例子说明,一个类Person,另一个类Car,如果Person的某个方法比如说drive,需要引用Car,则称Person类依赖于 Car类
Public Person{
...
public void drive(){
Car toyota=new Car("TOYOTA");
toyota.挂档;
toyota.踩油门;
toyota.打方向;
}
}
这其中的依赖关系,就导致了Person对象需要负责对象toyota的创建,甚至是整个生命周期的管理,而这样显然会带来耦合度高,不易维护等缺点,比如说要让这个男孩驾驶一辆Audi,则还需要修改类Person的代码。所以我们通常从外部传入一个Car对象,这就是所谓的依赖注入
Public Person{
...
Car toyota;
public Person(Car car){
toyota=car;
}
public void drive(){
toyota.挂档;
toyota.踩油门;
toyota.打方向;
}
}
但是直接在构造方法里面传递对象又会造成一个问题,随着后续业务增加也许又需要传入Phone,Computer试想一下如果一个工程中有5个文件使用了Person那是不是要改5个文件。
所以有的时候我们会直接通过set方法来注入对象,这就需要我们每次使用时都要做null判断,因为你可能会忘记为它set值,有没有更优美的解决方法呢?Dagger2来了。
dagger2的github地址:
https://github.com/google/dagger
使用步骤
1.添加依赖
implementation 'com.google.dagger:dagger:2.11'
annotationProcessor 'com.google.dagger:dagger-compiler:2.11'
People.java
public class People {
public People () {
System.out.println("a people created");
}
public void print(){
Log.d("sun"," i am people");
}
}
2.创建Module
什么是Module,你可以把它想象成一个工厂,可以向外提供一些类的对象,类名用@Module标注,方法用@Provides标注,类名和方法名没有特别规范
MainModule .java
@Module
public class MainModule {
@Provides
People providesPerson() {
return new People ();
}
}
3.创建MainComponent
MainComponent.java
@Component(modules = {MainModule.class})
public interface MainComponent {
void inject(MainActivity mainActivity);
}
4.重新Build项目
5.在MainActivity中将component 关联进去
public class MainActivity extends AppCompatActivity {
@Inject
People people;
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MainComponent mainComponent =DaggerMainComponent.builder().mainModule(new MainModule()).build();
mainComponent.inject(this);
people.print();
}
}
假定一个场景,现在People的构造方法改变了,我们给它增加了一个name属性和一个context属性
public class People {
Context context;
String name;
public People(Context context,String name) {
System.out.println("a people created");
this.name=name;
this.context=context;
}
public void print(){
Log.d("sun"," i am people"+name);
Toast.makeText(context,"i am people"+name,Toast.LENGTH_LONG).show();
}
}
相应的修改MainModule.java
@Module
public class MainModule {
public MainModule() {
}
@Provides
People providesPerson(Context context,String log){
return new People(context,log);
}
}
或者新建一个Moudle
@Module
public class SubMainModule {
@Provides
People providesPerson(Context context, String log){
return new People(context,log);
}
}
新建ContextComponent和ContextModule
@Module
public class ContextModule {
Context context;
public ContextModule(Context context) {
this.context = context;
}
@Provides
Context getContext(){
return context;
}
}
@Component(modules = {ContextModule.class})
public interface ContextComponent {
Context getContext();
}
同理创建StringComponent和StringModule。
然后修改MainComponent ,添加Component之间的依赖
@Component(dependencies = {StringComponent.class,ContextComponent.class},modules = {MainModule.class})
public interface MainComponent {
void inject(MainActivity mainActivity);
}
最后绑定Activity
StringComponent stringComponent=DaggerStringComponent.builder().stringModule(new StringModule("abc")).build();
ContextComponent contextComponent=DaggerContextComponent.builder().contextModule(new ContextModule(mainActivity)).build();
DaggerMainComponent.builder().mainModule(new MainModule()).stringComponent(stringComponent).contextComponent(contextComponent).build().inject(mainActivity);
@Qualifier
如果一个Moudle提供了多种创建对象的方式,可以通过自定义标签的方式指定使用哪种方式
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface PeopleWithContext {
}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface PeopleWithName {
}
在Moudler中分别注解提供对象的方法
// ...
@PersonWithContext
@Provides
public Person providesPersonWithContext(Context context) {
return new Person(context);
}
@PersonWithName
@Provides
public Person providesPersonWithName() {
return new Person("yxm");
}
在依赖注入的地方也使用标签注解
@PersonWithContext
@Inject
Person p1;
@PersonWithContext
@Inject
Person p2;
@Scope
@Scope可用于修饰自定义的注解,用@Scope修饰的注解来修饰
Moudle里面提供对象的方法会产生单例效果,但是注意必须给相应的Component提供注解,而且如果Moudle里面有多个提供对象的方法,那么每一个方法都会产生一个对象,实际上不是单例,@Singleton就是用@Scope修饰的注解
@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {
}
@ActivityScope
@Provides
Person providesPeople {
return new Person();
}
@ActivityScope
@Component(modules = {ActivityModule.class})
public interface ActivityComponent {
void inject(MainActivity mainActivity);
}
总结:
Dagger说白了给我们提供了灵活创建对象的方式,对象的创建是在一层一层的依赖中实现的,例如前面的例子,修改构造函数时,只需要修改相应的Moudle,并且在当前Moudle中提供创建对象的元素,或者重新创建新的Moudle和Component,然后添加Component依赖,然后修改绑定的元素的代码,乍一看,这岂不是更复杂,实际上,有一些被依赖的Component对象并不是在需要使用时就创建的,而是提前创建或者封装在一些工具类中,从而简化我们的代码