(1) 3.0之前引入插件如图所示
内容如下:
classpath'com.neenbedankt.gradle.plugins:android-apt:1.8'
(2)3.0 之后无需任何操作,只需要配置APP目录下的gradle即可
(1)3.0之前版本为
内容如下:
compile 'com.google.dagger:dagger:2.4'
apt 'com.google.dagger:dagger-compiler:2.4'
Provided'org.glassfish:javax.annotation:10.0-b28'
(2)3.0以后的gradle 版本
直接在dependencies下添加
compile 'com.google.dagger:dagger:2.4'
annotationProcessor "com.google.dagger:dagger-compiler:2.4"
compile 'org.glassfish:javax.annotation:10.0-b28'// 添加java 注解库
最后就sync now 就完成了dagger 在项目中的引入。
1. 编写一个需要注入到view层的实体类
写一个textbean类用作依赖对象,包含一个content属性
public class TextBean {
private String content;
public String getContent() {
return content; }
public void setContent(String content) {
this.content = content;
}}
2. 写一个Module类
假如我们的需求是想在MainActivity里获取到一个实例化完成,并且它的content属性有内容的TextBean对象,那么这个Module 相当一个加工厂,把我们需要的对象给我们创建出来。代码如下:
@Module //module的注解标记
public class MainMoudle {
@Provides //提供返回我们想要的Textbean的方法的注释标记
@Singleton //单例的注释标记
public TextBean getTextBean( ){
TextBean textBean=new TextBean( );
textBean.setContent("我的daager2 第一个实体");
return textBean;
}
}
(1)@Module以表明该类是Module类,这样Dagger2才能识别.
(2)@Provides的作用是声明Module类中哪些方法是用来提供依赖对象的。
当Component类需要依赖对象时,他就会根据返回值的类型来在有@Provides注解的方法中选择调用哪个方法.在一个方法上声明@Provides注解,就相当于创建了一条生产线,这条生产线的产物就是方法的返回值类型.有了这条生产线,供应商就能提供这种类型的商品了,当商店老板发现有人需要这种类型的商品时,供应商就可以提供给他了
3. 写一个Component接口
@Component(modules = MainMoudle.class)//绑定对应的module类
public interface MainCompont {
void inject(MainActivity mainActivity);//注入方法
}
(1)@Component注解有modules和dependencies两个属性,
这两个属性的类型都是Class数组,
1, modules的作用就是声明该Component含有哪几个Module,当Component 需要 某个依赖对象时,就会通过这些Module类中对应的方法获取依赖对象
2,dependencies属性则是声明Component类的依赖关系
4. 在MainActivity中声明
public class MainActivity extends AppCompatActivity {
private TextView textView;
@Inject
TextBean textBean;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MainCompont mainCompont= DaggerMainCompont.builder().mainMoudle(new MainMoudle( )).build();
mainCompont.inject(this);
// 子类依赖对象 ,并注入
textView= ((TextView) findViewById(R.id.my_name_tv_id));
textView.setText(textBean.getContent());
Log.e("Dagger2的检测one ",textBean.toString());
}
执行结果:
基本用法总结图
使用场景 :如果两个@Provides的注释的方法,返回值的类型是一样的,那么在MainActivity里的两个@Inject 注入的同一个实体类型对象时候,
要通过@Named区分,或者通过@Qulifier自定义注解:不然就会报错无法编译
一,通过@named区分
1.对于Moudle类的注入类
@Provides
@Singleton
@Named("textone")
public TextBean getTextBean( ){
TextBean textBean=new TextBean( );
textBean.setContent("我的daager2 第一个实体");
return textBean;
}
@Provides
@Singleton
@Named("texttwo")
public TextBean getTextBean2(){
TextBean textBean=new TextBean( );
textBean.setContent("我的dagger2 第一个实体的第二个procides的方法");
return textBean;
}
2.对于MainActivity的注入类
public class MainActivity extends AppCompatActivity {
private TextView textView;
private Button buttons;
@Inject
@Named("textone")
TextBean textBean;
@Inject
@Named("texttwo")
TextBean textBean2;
@Inject
TwoBean twoBean;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MainCompont mainCompont= DaggerMainCompont.builder().mainMoudle(new MainMoudle( )).build();
mainCompont.inject(this);
// 子类依赖对象 ,并注入
textView= ((TextView) findViewById(R.id.my_name_tv_id));
buttons= ((Button) findViewById(R.id.onclick_bt_id));
textView.setText(textBean.getContent());
Log.e("Dagger2的检测one ",textBean.toString()+"two id="+textBean2.toString());
Log.e("Dagger2的第二个实体 ",twoBean.getContent()+"____id="+twoBean.toString());
}
});
}
}
二,通过@Qulifier自定义注解区分
@Qulifier功能和@Named一样,并且@Named就是继承@Qulifier的
1. 自定义注解接口内容
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface TextonePri {
}
2. Module类使用
@Provides
@Singleton
@TextonePri
public TextBean getTextBean( ){
TextBean textBean=new TextBean( );
textBean.setContent("我的daager2 第一个实体");
return textBean;
}
3,在注入类,MainActivity的使用
@Inject
@TextonePri
TextBean textBean;
@Inject
@Named("texttwo")
TextBean textBean2;
在前面中提到@Singleton注解,该注解能够使同一个Component中的对象保持唯一,即单例。
如下方式:
@Provides // 关键字,标明该方法提供依赖对象
@Singleton
Person providerPerson(Context context){
return new Person(context);
}
Module中,对应方法中添加@Singleton注解,同时其所在的Component中,类生命上也需要添加注解
@Singleton
@Component(modules = MainModule.class) // 作为桥梁,沟通调用者和依赖对象库public interface MainComponent {
}
如果我们看这个意思,感觉其内部应该做了很多的实现,用以达到单例。其实,没我们想的那么复杂。
看一下@Singleton的实现
@Scope //注明是Scope
@Documented //标记在文档
@Retention(RUNTIME) // 运行时级别
public @interface Singleton {}
通过@Scope定义的一个新的注解。
在之前的,我们知道该单例是依托于他所在的Component组件。那么我们是否可以这样理解,因为方法上添加的@Scope标记的注解和Component上添加的@Scope标记的注解相同(确实相同,同为@Singleton),就表明了该方法提供的实例对象在Component保持唯一。保持唯一的条件是通过@Scope标记的注解相同。
通过在上面的依赖层级上,Android中通常定义两个生命周期。
全局的生命周期PerApp
/**
* 全局的生命周期单例
*/@Scope@Documented@Retention(RetentionPolicy.RUNTIME)public @interface PerApp {
}
在使用中完全和@Singleton相同。
@Modulepublic class AppModule {
private Context mContext;
public AppModule(Context context){
mContext = context;
}
@Provides
@PerApp // 添加该标记表明该方法只产生一个实例
Context providesContext(){
// 提供上下文对象
return mContext;
}
}
@PerApp // 因为Module 中使用了该标记,所以需要在此添加@Component(modules = AppModule.class)public interface AppComponent {
// 向其下层提供Context 对象
Context proContext();
}
因为单例的依托于他所在的Component中,所以需要在Application中进行实例化。
public class App extends Application {
// 为什么可以使用静态
public static AppComponent appComponent;
@Override
public void onCreate() {
super.onCreate();
// 实例化
appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build();
}
}
为什么可以使用静态的,因为该AppComponent对象的生命周期是整个App。那么在使用中,其所在Module中的实例化对象,可以保持全局单例。
一个Activity的生命周期PerActivity
有全局的单例,而对于一个Activity,他也有些对象需要保持单例。我们需要定义该注解。
/**
* Activity 单例生命周期
*/@Scope@Documented@Retention(RetentionPolicy.RUNTIME)public @interface PerActivity {
}
会发现,除了定义名不一样,其余都和PerApp一样。在前面,说过这样一句话:保持唯一的条件是通过@Scope标记的注解相同。
@Modulepublic class ActivityMoudule {
@PersonForContext
@Provides
@PerActivity // 添加标记,生命其所构造的对象单例
Person providePersonContext(Context context){
// 此方法需要Context 对象
return new Person(context);
}
.....
}
@PerActivity // ActivityMoudule 中使用了该标记@Component(dependencies = AppComponent.class,modules = ActivityMoudule.class)public interface ActivityComponent {
// 注入
void inject(MainActivity activity);
}
使用方式,因为其所保持的单例是在Activity中,具体使用如下。
public class MainActivity extends AppCompatActivity{
@PersonForContext // 标记
@Inject
Person person;
@PersonForName // 标记
@Inject
Person person2;
/**
* 不使用静态的,因为该Component只是针对于该Activity,而不是全局的
*/
ActivityComponent activityComponent;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
activityComponent = DaggerActivityComponent.builder()
.appComponent(App.appComponent) // 添加了全局的AppComponent组件,可以使用全局的实例化对象
.activityMoudule(new ActivityMoudule())
.build();
activityComponent.inject(this);
对于具有依赖关系的Component,不能使用相同的Scope,如果使用相同的会带来语意不明
public class MainActivity extends AppCompatActivity{
@PersonForContext // 标记
@Inject
Lazy
@PersonForName // 标记
@Inject
Provider
/**
* 不使用静态的,因为该Component只是针对于该Activity,而不是全局的
*/
ActivityComponent activityComponent;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
activityComponent = DaggerActivityComponent.builder()
.appComponent(App.appComponent) // 添加了全局的AppComponent组件
.activityMoudule(new ActivityMoudule())
.build();
activityComponent.inject(this);
Person person = lazyPerson.get();// 调用该方法时才会去创建Person,以后每次调用获取的是同一个对象
// 调用该方法时才回去创建Person1,以后每次调用都会重新加载Module中的具体方法,根据Module中的实现,可能相同,可能不相同。
Person person1 = providerPerson.get();
}
}
参考链接:
https://www.jianshu.com/p/1d84ba23f4d2
https://blog.csdn.net/lisdye2/article/details/51942511
https://dreamerhome.github.io/2016/07/07/dagger/?utm_source=tuicool