说到Dagger2,有人说他是一件神器,非常好用,但也有人觉得他学习成本太高,在项目中使用会平白的多写好多类和接口,非常繁琐,其实一开始的时候,我并没有接触过Daggers2,但是最近在做项目的时候,接触到了这件神器,我使用过后的第一个感觉,就是,"这不是Spring boot么?",不错,如果有同学使用过spring boot开发过web项目,那么在使用Dagger2的时候,肯定感觉会非常亲切了,可以说,spring boot的核心就是依赖注入,配置上几个注解之后,就可以很方便的开发web项目,他与Dagger2不同的是,spring boot是一个框架,他的注解都已经配置好了,而且针对特定功能的模块会有特定的注解,比如业务层service就可以使用@Service,控制层可以使用@Controller,而Dagger2就那么几个注解,需要我们自己去配置好,进行类之间的关联,以上,仅仅是我自己的观点,可能有误;
好吧,说了这么多,直接说使用步骤吧:
1.添加依赖:(android studio2.2以上)
//dagger2
compile 'com.google.dagger:dagger:2.4'
annotationProcessor 'com.google.dagger:dagger-compiler:2.4'
2.假定有这么一个场景:有一个艺术家,他可以唱歌,也会跳舞,那么代码可以这么写
package com.example.pengganggui.dagger2test;
/**
* Created by pengganggui on 2018/8/27.
* 舞蹈
*/
public class Dance {
public Dance() {
}
@Override
public String toString() {
return "芭蕾舞";
}
}
package com.example.pengganggui.dagger2test;
/**
* Created by pengganggui on 2018/8/27.
*/
public class Song {
public Song() {
}
@Override
public String toString() {
return "东风破";
}
}
package com.example.pengganggui.dagger2test;
/**
* Created by pengganggui on 2018/8/27.
* 艺术家
*/
public class Arthritis {
Song song=null;
Dance dance=null;
public void play(){
song=new Song();
dance=new Dance();
System.out.println("我是艺术家,我会跳"+song.toString()+"我会唱"+dance.toString());
}
}
可以看见,在艺术家里需要new 两个对象才能实现相应的功能,这不符合软件开发的基本思想,低耦合,高内聚,比如说,此时,艺术家会的舞蹈歌曲不仅仅只是芭蕾舞和东风破了,那么我们需要修改Song和Dance类,因为Arthritis是和其紧紧依赖在一起的,所以,响应的Arthritis也需要改变,如果类多了,那么可以想象,工作量很大,并且还容易出错,代码的扩展性不大,这时候,依赖注入就应运而生了;
我们现在可以这么写:
package com.example.pengganggui.dagger2test;
import javax.inject.Inject;
/**
* Created by pengganggui on 2018/8/27.
* 舞蹈
*/
public class Dance {
@Inject
public Dance() {
}
@Override
public String toString() {
return "芭蕾舞";
}
}
package com.example.pengganggui.dagger2test;
import javax.inject.Inject;
/**
* Created by pengganggui on 2018/8/27.
*/
public class Song {
@Inject
public Song() {
}
@Override
public String toString() {
return "东风破";
}
}
package com.example.pengganggui.dagger2test;
import javax.inject.Inject;
/**
* Created by pengganggui on 2018/8/27.
* 艺术家
*/
public class Arthritis {
@Inject
Song song=null;
@Inject
Dance dance=null;
@Inject
public Arthritis() {
}
public String play(){
return "我是艺术家,我会跳"+song.toString()+"我会唱"+dance.toString();
}
}
@Inject 注解就如同一个标签,或者说它是一个记号,它是给 Dagger2 看的。它运用的地方有两处。
-
@Inject 给一个类的相应的属性做标记时,说明了它是一个依赖需求方,需要一些依赖。
-
@Inject 给一个类的构造方法进行注解时,表明了它能提供依赖的能力。
但是,仔细想一想,@Inject可以标记一个属性需要一些依赖或者标记一个类可以提供依赖,但是这些依赖在哪呢,不知道,我需要一个依赖,你可以提供依赖,那么我给你提供依赖就可以了,但是,这两者之间仅仅通过@Inject一个注解是达不到效果的,所以,还需要一个@Component注解,来建立两者关系;
package com.example.pengganggui.dagger2test;
import dagger.Component;
/**
* Created by pengganggui on 2018/8/27.
*/
@Component()
public interface ArthritisInterface {
Arthritis play();
}
这样,就有了联系的纽带了,这时,我们在主活动调用:
package com.example.pengganggui.dagger2test;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Arthritis play = DaggerArthritisInterface.builder().build().play();
findViewById(R.id.btn_test).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this,play.play(),Toast.LENGTH_LONG).show();
}
});
}
}
所以,使用@Inject和@Component注解就可以使用Dagger2了;
但是,如果真的有这么简单的话,那么也不会让这么多人头疼了,所以,我们再想一想,@Inject需要注解在类的构造方法上,才能提供依赖,那么就有一个问题了,并不是所有的类我们都可以再其构造方法上添加@Inject的,比如第三方库和Java的标准库,这些都是不允许你修改的,这时,dagger2就提供了其它的注解;
@Provides 和 @Module
Provide 本身的字面意思就是提供,显然在 Dagger2 中它的作用就是提供依赖。
Module 是模块的意思,Dagger2 中规定,用 @Provides 注解的依赖必须存在一个用 @Module 注解的类中。
我们改一改代码:此时艺术家不仅仅只会唱一首歌和一支舞了,我们需要动态的去改变歌名和舞名,我们可以这么写:
package com.example.pengganggui.dagger2test;
import javax.inject.Inject;
/**
* Created by pengganggui on 2018/8/27.
*/
public class Song {
String songName="";
@Inject
public Song() {
}
public Song(String songName){
this.songName=songName;
}
@Override
public String toString() {
return songName;
}
}
package com.example.pengganggui.dagger2test;
import javax.inject.Inject;
/**
* Created by pengganggui on 2018/8/27.
* 舞蹈
*/
public class Dance {
String danceName="";
@Inject
public Dance() {
}
public Dance(String danceName) {
this.danceName=danceName;
}
@Override
public String toString() {
return danceName;
}
}
package com.example.pengganggui.dagger2test;
import dagger.Module;
import dagger.Provides;
/**
* Created by pengganggui on 2018/8/27.
*/
@Module
public class ArthritisPlatform {
@Provides
public Song providesSong(){
return new Song("我的太阳");
}
@Provides
public Dance providesDance(){
return new Dance("拉丁舞");
}
}
这就是@Module和@Provides的用法,向外界提供依赖,那么Component里面怎么关联呢?
package com.example.pengganggui.dagger2test;
import dagger.Component;
/**
* Created by pengganggui on 2018/8/27.
*/
@Component(modules = ArthritisPlatform.class)
public interface ArthritisInterface {
Arthritis play();
}
这样就大功告成了,主活动的代码不需要改,同时要注意,当一个类同时被Modle和Inject提供,那么会以@Module为主;
上面四个注解足以应对大部分的日常的开发了,不过Dagger2提供的可不止这些:
@Singleton
用 @Singleton 标注在目标单例上,然后用 @Singleton 标注在 Component 对象上。就可以实现单例模式
@Singleton其实是被@Scope元注解注解的一个注解,那么@Scope其实就是代表作用域,他规定了这个注解的作用域的大小,我们上面说了,@Singleton需要标注在目标单例和component上,那么为什么需要标注在Component上呢,标注在Component上代表这个singleton只能在component的范围内有效;