一.概述
- Dagger2是一个基于JSR-330标准的依赖注入框架,在编译期间自动生成代码,负责依赖对象的创建。
- Java 依赖注入标准 JSR-330 简介概念
JSR-330 是 Java 的依赖注入标准。定义了如下的术语描述依赖注入:
A 类型依赖 B类型(或者说 B 被 A 依赖),则 A类型 称为”依赖(物) dependency”
运行时查找依赖的过程,称为”解析 resolving“依赖
如果找不到依赖的实例,称该依赖是”不能满足的 unsatisfied”
在”依赖注入 dependency injection”机制中,提供依赖的工具称为”依赖注入器 dependency injector”
- 作用:管理对象及其生命周期
- 好处:统一管理对象,对象初始化一次即可,降低程序耦合。比如一个对象调用一千次,如果new的话需要一千次,现在只需要去找dagger2要即可,即使修改也就去找Dagger2修改一次即可。
- 使用场景:应用在比较复杂或者规模较大的App,简单App没必要大材小用。
-
介绍
①Module:提供对象的,注入到需要的地方。一个App中有很多module,比如httpObject、GlideObject等。
②Component:用于注入对象,从Module注入到需要的地方,比如controller等
dagger2.png
二.具体使用
- 导入依赖
implementation 'com.google.dagger:dagger:2.17'
annotationProcessor 'com.google.dagger:dagger-compiler:2.17'
- 建包及使用(di:注入包、object:对象包)
①在object包创建对象类
public class HttpObject{
}
②在di包创建类HttpModule
/**
* 提供Http对象
*
*/
@Module
public class HttpModule {
@Provides
public HttpObject provodeHttpObject() {
return new HttpObject();
}
}
③在di包创建AnflyComponet接口用来注入对象
/**
* 提供依赖注入的类
*/
@Component(modules = {HttpModule.class})
public interface AnflyComponet {
/**
* 提供注入方法,注意参数不能使用多态
*
* @param mainActivity
*/
void injectMainactivty(MainActivity mainActivity);
}
④重新编译整个工程RebuildProject,生成DaggerAnflyComponet(实现原理是atp),在MainActivity中创建注入器并调用其方法,就可以通过@Inject
注入HttpObject对象
public class MainActivity extends AppCompatActivity {
@Inject
HttpObject httpObject;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//生成DaggerAnflyComponet注解处理器
DaggerAnflyComponet.create().injectMainactivty(this);
Log.e("TAG", "httpObject=" + httpObject.hashCode());
}
}
3.原理简介
刚才在MainActivity中使用DaggerAnflyComponet创建component,使用的使用create方式
①我们点击源码进去:
public static AnflyComponet create() {
return new Builder().build();
}
②create最终使用的是构建者模式实现的,所以我们也可以直接在MainActivity中使用构建者模式创建注解处理器
AnflyComponet anflyComponet = DaggerAnflyComponet.builder()
.httpModule(new HttpModule())
.dataBaseModule(new DataBaseModule())
.build();
anflyComponet.injectMainactivty(this);
③点击.httpModule(new HttpModule())
public Builder httpModule(HttpModule httpModule) {
this.httpModule = Preconditions.checkNotNull(httpModule);
return this;
}
通过构建者模式返回自身,当然这里做了非空判断:Preconditions.checkNotNull(httpModule)
ublic static <T> T checkNotNull(T reference) {
if (reference == null) {
throw new NullPointerException();
}
return reference;
}
④点击build看看做了什么事情
public AnflyComponet build() {
if (httpModule == null) {
this.httpModule = new HttpModule();
}
return new DaggerAnflyComponet(this);
}
先判断httpModule 是否为空,如果为空就新建一个,最后返回DaggerAnflyComponet
至此,相当于把需要的对象在内存中生成。
⑤点击anflyComponet.injectMainactivty(this)跳转到我们自己写的接口方法
1582989016(1).png
该接口有自己的实现类,我们看看实现类
@Override
public void injectMainactivty(MainActivity mainActivity) {
injectMainActivity(mainActivity);
}
private MainActivity injectMainActivity(MainActivity instance) {
MainActivity_MembersInjector.injectHttpObject(
instance, HttpModule_ProvodeHttpModuleFactory.proxyProvodeHttpModule(httpModule));
return instance;
}
通过MainActivity成员注射器 MainActivity_MembersInjector注入HttpObject
⑥声明HttpObject为单例
@Module
@Singleton
public class HttpModule {
@Singleton
@Provides
public HttpObject provodeHttpModule() {
return new HttpObject();
}
}
@Singleton
@Component(modules = {HttpModule.class, DataBaseModule.class})
public interface AnflyComponet {
/**
* 提供注入方法,注意参数不能使用多态
*
* @param mainActivity
*/
void injectMainactivty(MainActivity mainActivity);
void injectSecondactivty(SecondActivity secondActivity);
}
现在新建一个SecondActivity同样打印HttpObject对象的hashcode,MainActivit打印两个HttpObject对象的hashcode。
MainActivit:
public class MainActivity extends AppCompatActivity {
@Inject
HttpObject httpObject;
@Inject
HttpObject httpObject2;
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
//生成DaggerAnflyComponet注解处理器
//第一中写法
DaggerAnflyComponet.create().injectMainactivty(this);
//第二种写法
AnflyComponet anflyComponet = DaggerAnflyComponet.builder()
.httpModule(new HttpModule())
.dataBaseModule(new DataBaseModule())
.build();
anflyComponet.injectMainactivty(this);
Log.e("TAG", "MainActivity httpObject=" + httpObject.hashCode());
Log.e("TAG", "MainActivity httpObject2=" + httpObject2.hashCode());
}
private void initView() {
tv = (TextView) findViewById(R.id.tv);
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivity(intent);
}
});
}
}
SecondActivity:
public class SecondActivity extends AppCompatActivity {
@Inject
HttpObject httpObject;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
DaggerAnflyComponet.create().injectSecondactivty(this);
Log.e("TAG", "SecondActivity httpObject=" + httpObject.hashCode());
}
}
结果是:
02-29 23:50:03.339 3667-3667/? E/TAG: MainActivity httpObject=745396538
02-29 23:50:03.339 3667-3667/? E/TAG: MainActivity httpObject2=745396538
02-29 23:50:05.176 3667-3667/com.anfly.dagger2 E/TAG: SecondActivity httpObject=951541497
结论:同一个activity中是同一个对象,但是不同activity中不是同一个对象,现在只达到了局部单例,但是项目中是需要全局单例的,怎么办呢??
⑦实现全局单例
方法:所有类使用同一个注射器,即在application中获取注射器,在不同类中去注入
创建一个application
public class DaggerApplication extends Application {
private static DaggerApplication daggerApplication;
private AnflyComponet anflyComponet;
@Override
public void onCreate() {
super.onCreate();
daggerApplication = this;
anflyComponet = DaggerAnflyComponet.create();
}
public static DaggerApplication getDaggerApplication() {
return daggerApplication;
}
public AnflyComponet getAnflyComponet() {
return anflyComponet;
}
}
在MainActivit中:
public class MainActivity extends AppCompatActivity {
@Inject
HttpObject httpObject;
@Inject
HttpObject httpObject2;
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
//生成DaggerAnflyComponet注解处理器
//第一中写法
// DaggerAnflyComponet.create().injectMainactivty(this);
//第二种写法
// AnflyComponet anflyComponet = DaggerAnflyComponet.builder()
// .httpModule(new HttpModule())
// .dataBaseModule(new DataBaseModule())
// .build();
// anflyComponet.injectMainactivty(this);
DaggerApplication.getDaggerApplication().getAnflyComponet().injectMainactivty(this);
Log.e("TAG", "MainActivity httpObject=" + httpObject.hashCode());
Log.e("TAG", "MainActivity httpObject2=" + httpObject2.hashCode());
}
private void initView() {
tv = (TextView) findViewById(R.id.tv);
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivity(intent);
}
});
}
}
在SecondActivity中:
public class SecondActivity extends AppCompatActivity {
@Inject
HttpObject httpObject;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
// DaggerAnflyComponet.create().injectSecondactivty(this);
DaggerApplication.getDaggerApplication().getAnflyComponet().injectSecondactivty(this);
Log.e("TAG", "SecondActivity httpObject=" + httpObject.hashCode());
}
}
结果:
03-01 00:04:34.301 3817-3817/com.anfly.dagger2 E/TAG: MainActivity httpObject=745396538
03-01 00:04:34.301 3817-3817/com.anfly.dagger2 E/TAG: MainActivity httpObject2=745396538
03-01 00:04:36.139 3817-3817/com.anfly.dagger2 E/TAG: SecondActivity httpObject=745396538
结论:使用同一个注射器实现的全局单例
4.不同Component将对象同一个activity
不同的Component不能给同一个activity注入对象,实在想注入同一个activity只能想办法组装成一个component。
怎么组装呢?创建一个主component,其他次component可以通过dependencies = PresenterComponet.class添加到主component
①对象类
public class PresenterObject {
}
②提供对象的类
@Module
public class PresenterModule {
@Provides
public PresenterObject providePresenter() {
return new PresenterObject();
}
}
③注射器
@Component(modules = {PresenterModule.class})
public interface PresenterComponet {
/**
* 提供注入方法,注意参数不能使用多态
*
* 但是这里是从component,所以该方法不能用
*
* @param
*/
// void injectMainactivty(MainActivity mainActivity);
// void injectSecondactivty(SecondActivity secondActivity);
public PresenterObject providePresenter();
}
这里需要注意的是,不需要在写一遍injectMainactivty(MainActivity mainActivity),因为在主component已经写过一遍了,只需要提供一个方法(来自module中方法);
④主component修改
@Singleton
@Component(modules = {HttpModule.class, DataBaseModule.class},
dependencies = {PresenterComponet.class})
public interface AnflyComponet {
/**
* 提供注入方法,注意参数不能使用多态
*
* @param mainActivity
*/
void injectMainactivty(MainActivity mainActivity);
void injectSecondactivty(SecondActivity secondActivity);
}
第三行多了dependencies = {PresenterComponet.class},他表示这个主component引入了次component。
⑤RebuildProject
在DaggerApplication中添加一行:创建注入器
@Override
public void onCreate() {
super.onCreate();
daggerApplication = this;
anflyComponet = DaggerAnflyComponet.builder()
.httpModule(new HttpModule())
.presenterComponet(DaggerPresenterComponet.create())
.build();
}
现在就可以直接在MainActivity中直接调用presenterObject了。
- 将PresenterObject设置为单例。如果按照以前的写法,module和component添加注解@Singleton就会报错:
错误: [Dagger/IncompatiblyScopedBindings] com.anfly.dagger2.di.PresenterComponet (unscoped) may not reference scoped bindings:
@Provides @Singleton com.anfly.dagger2.object.PresenterObject com.anfly.dagger2.di.PresenterModule.providePresenter()
原因:使用dependencies的时候,多个组件之间的Scope不能相同,没有Scope的不能依赖有Scope的组件。
Scope是什么呢?用来标识组件,方便进行依赖关系绑定
解决方案:我们可以使用scope替换掉所用的@Singleton就能解决问题了
①创建一个scope文件,再创建一个APPScope类,这个代码是@Singleton源码
@Scope
@Documented
@Retention(RUNTIME)
public @interface AppScope {
}
首先直接将主component相关的@Singleton替换为@AppScope
@Module
public class HttpModule {
@AppScope
@Provides
public HttpObject provideHttpModule() {
return new HttpObject();
}
}
@AppScope
@Component(modules = {HttpModule.class, DataBaseModule.class},
dependencies = {PresenterComponet.class})
public interface AnflyComponet {
/**
* 提供注入方法,注意参数不能使用多态
*
* @param mainActivity
*/
void injectMainactivty(MainActivity mainActivity);
void injectSecondactivty(SecondActivity secondActivity);
}
每一个组件或者component对应一个Scope,为presenter创建一个scope
@Scope
@Documented
@Retention(RUNTIME)
public @interface PresenterSingleScope {
}
然后
@PresenterSingleScope
@Component(modules = {PresenterModule.class})
public interface PresenterComponet {
/**
* 提供注入方法,注意参数不能使用多态
*
* 但是这里是从component,所以该方法不能用
*
* @param
*/
// void injectMainactivty(MainActivity mainActivity);
// void injectSecondactivty(SecondActivity secondActivity);
public PresenterObject providePresenter();
}
@Module
public class PresenterModule {
@PresenterSingleScope
@Provides
public PresenterObject providePresenter() {
return new PresenterObject();
}
}
打印结果:
03-01 04:03:18.332 5482-5482/com.anfly.dagger2 E/TAG: MainActivity httpObject=745396538
03-01 04:03:18.332 5482-5482/com.anfly.dagger2 E/TAG: MainActivity httpObject2=745396538
03-01 04:03:18.332 5482-5482/com.anfly.dagger2 E/TAG: MainActivity presenterObject=533813739
03-01 04:03:21.948 5482-5482/com.anfly.dagger2 E/TAG: SecondActivity httpObject=745396538
03-01 04:03:21.948 5482-5482/com.anfly.dagger2 E/TAG: SecondActivity presenterObject=533813739
结论:我们实现了多个组件或者component向同一个activity注入对象,并且实现全局单例。
三.高级用法
出来混迟早要还的,技术债Dagger2:Android篇
可能是东半球最好的dagger2文章
浅析Dagger2的使用
网友评论