想学习下Dagger2 ,搜了很多资料但都是附带着RxJava等其他东西,让楼主学习起来比较费时(可能比较笨),本人也没有使用过Dagger1.x,所以学习Dagger2的更是举步维艰啊。
看了很多资料,终于懂了一点,下面主要说说Dagger2的使用过程及自己见解,加深印象。说的不对的也请读者指正。
Dagger2是Android的一个依赖注入框架,可用于模块间解耦,提高代码的健壮性和可维护性。
Dagger2是基于一个有向无环图结构的依赖注入库,因此dagger2的使用过程中不能出现循环依赖的现象。
以下都已 Android studio开发工具为例。
一、引用
在module的build.gradle添加如下两个模块 :
a、apply plugin: 'com.neenbedankt.android-apt'
b、compile 'com.google.dagger:dagger:2.5'
compile 'com.google.dagger:dagger-compiler:2.5'
在project的build.gradle中dependencies 添加
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
如:
buildscript { repositories { jcenter() } dependencies { classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4' } }
apt相关的依赖一定要加上,要不生成不了对应所需文件 Dagger+"" 等。
2、Component和Module
Dagger2 通过注解来工作,定义不同的角色,主要的注解包括:@Component 、@Module 、@Inject、@Provides 、@Scope 、@SubComponent 等。
Component和Module是Dagger2的两个主要注解。
module是生产对象的地方,即是生产方,需要什么样的对象都要在这里生产
Component 是联系module和module使用场景的桥梁,module生产的对象需要在哪里使用要靠Component来提供、暴露,即提供方。使module和module的使用场景达到了一个解耦。
dagger2的使用
模拟一个场景,类A需要在DaggerActivity使用 。
正常情况:
A类 :
public class A {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
DaggerActivity :
public class DaggerActivity extends Activity {
private static final String TAG = "DaggerActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityComponent aComponenet = DaggerActivityComponent.builder()
.aModule(new AModule())
.build();
A a = new A();
a.setAge(10);
Log.d(TAG, "onCreate --> a.getAge() : : " + a.getAge()); a.setAge();
}
}
使用Dagger2:
A类 :
public class A {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
增加一个Module , AModule类 :
@Module
public class AModule {
@Provides
A provideA() {
return new A();
}
}
Module 类需要使用@Module注解,标记这是一个生产对象的地方,这里仅生产了对象 A。
增加一个Component ,AComponent类 :
@Component(modules = AModule.class)
public interface AComponent{
A a();
}
Component类需要使用@Component注解,并添加modules依赖,标记提供哪些对象,为哪些Module提供桥梁 。modules可以提供多个,写法是 modules = {AModule.class,A2Module.class}等。Component也可以依赖其它Component,实现@Component(dependencies = {A2Component.class,A3Component.class} modules = {AModule.class, A2Module.class})
使用,DaggerActivity :
public class DaggerActivity extends Activity {
private static final String TAG = "DaggerActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AComponentaComponenet = DaggerAComponent.builder()
.aModule(new AModule())
.build();
A a = aComponenet.a();
a.setAge(10);
}
}
这样就基本实现了Dagger2的使用,但我们发现这时并没有达到很好的解耦效果。下面再介绍两种优化 :
使用Dagger2 二 :
使用@Inject注解
A2 类 :
public class A2 {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
基本没变化
A2Module :
@Module
public class A2Module {
@Provides
A2 povideA2() {
return new A2();
}
}
A2Component :
@Component(modules = A2Module.class)
public interface A2Component {
void inject(DaggerActivity mainActivity);
}
这里多了一个inject()方法,参数为提供A2实例的地方,即使用场景。相比AComponent主动暴露A实例的方式,解耦了一些。
使用
DaggerActivity :
public class DaggerActivity extends Activity {
private static final String TAG = "DaggerActivity";
@Inject
A2 aaa2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DaggerA2Component.builder()
.a2Module(new A2Module())
.build()
.inject(this);
aaa2.setAge(20);
aaa2.getAge();
Log.d(TAG, "onCreate --> aaa2.getAge() : : " + aaa2.getAge());
}
}
这里看到 通过@Inject 注解来能达到实例化 A2对象的目的。DaggerA2Component的inject()就是告诉Dagger2在哪里实例化A2对象,这里是在DaggerActivity,并将对象赋给aaa2引用。 解耦更彻底了一些 。
还能更简化一些吗 ??
Dagger2 三 :
A3类 :
public class A3 {
@Inject
public A3() {
}
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
注意这里 在A3的构造函数上使用了 @Inject注解 。
A3Module 可以没有
那么 A3Component也就没有了。 .(没有桥头,要桥梁干么呢)
使用 DaggerActivity
public class DaggerActivity extends Activity {
private static final String TAG = "DaggerActivity";
@Inject
A3 aaa3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
aaa3.setAge(30);
aaa3.getAge();
Log.d(TAG, "onCreate --> aaa3.getAge() : : " + aaa3.getAge());
}
}
这里A3的初始化通过@Inject注解来实现,但并没有通过Component来告诉Dagger2在哪里实例化A3并赋值给谁。 这主要依赖在A3的构造函数中添加了@Inject注解,当需要实例化一个@Inject注解的对象时,就去遍历来实例化对应的对象。
这样解耦工作完全实现了。
看完示例三,可以发现Dagger2的优势完全体现出来了吧。
通过上面的实例可以发现示例三比示例二更简洁,那么Module注解是不是可以不要了呢 ?
什么时候使用Module,什么时候使用@Inject
一般系统的 、SDK的、第三方库提供的对象用Module (你没法在人家的构造函数上添加@Inject啊)
自定义的对象用Inject 定义一个子类继承系统、SDK、第三方库的对象,这时也可以使用Inject。
Component间的依赖
依赖一个Component时父Component需要将提供的对象暴露出来,否则子Component获取不到
@Component(modules = {AModule.class, A2Module.class})
public interface AComponent {
A a();
}
@Component(dependencies = AComponent.class, modules = A2Module.class)
public interface A2Component {
void inject(DaggerActivity mainActivity);
}
AComponent暴露了A对象,这样A2Component才能获取到A。
@Scope注解
这个注解是用来划分作用域的(在哪儿使用,使用范围),意思是画出一块区域来,生产的东西如果限定在此作用域,那都放到这里,作用域的场景类(如Activity、Fragment、Application)如果需要这个实例,就来这个作用域来取,有就直接使用,没有就先创建,放到作用域供下次使用。
dagger2自已有个@Scope注解,叫@Singleton,就是大家都熟悉的单例模式
可以自定义@Scope注解,比如限定生产出的某个对象只能在Activity中、Application中使用、Fragment中使用等等。。
定义一个Activity作用域的注解
@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface PerActivity {
}
PerActivity的使用
public class A2 {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class A3 {
@Inject
public A3() {
}
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class A4 {
@Inject
public A4() {
}
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
@Module
public class A2Module {
@Named("李四")
@Provides
A2 povideALisi() {
return new A2(21);
}
@Named("张三")
@Provides
A2 povideAZhangSan() {
return new A2(25);
}
@PerActivity
@Provides
A4 provideA4() {
return new A4();
}
@Provides
A3 provideA3() {
return new A3();
}
}
注意这里只给 provideA4()方法添加了@PerActivity注解 。
@PerActivity
@Component(dependencies = ActivityComponent.class, modules = A2Module.class)
public interface A2Component {
void inject(DaggerActivity mainActivity);
}
依赖A2Module的对应Component也要添加@PerActivity注解。
public class DaggerActivity extends Activity {
private static final String TAG = "DaggerActivity";
@Inject
A4 aaa4;
@Inject
A4 testa4;
private Button nextBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dagger_layout);
DaggerA2Component.builder()
.a2Module(new A2Module())
.build()
.inject(this);
aaa4.setAge(30);
Log.d(TAG, "onCreate --> aaa4.getAge() : : " + aaa4.getAge());
Log.d(TAG, "onCreate --> testa4.getAge() : : " + testa4.getAge());
testa4.setAge(50);
Log.d(TAG, "onCreate --> 2 aaa4.getAge() : : " + aaa4.getAge());
Log.d(TAG, "onCreate --> 2 testa4.getAge() : : " + testa4.getAge());
Log.d(TAG, "onCreate ------------------------------------------> : ");
}
}
可以发现这时aaa4和testa4两个对象会相互影响,改变一个,另一个也被修改,其实为同一个对象,为什么会这样呢??
我们来看下Dagger2自动生成的DaggerA2Component类(这里只捡主要代码粘贴):
public final class DaggerA2Component implements A2Component {
private Provider<A2> povideAZhangSanProvider;
private Provider<A2> povideALisiProvider;
private Provider<A3> provideA3Provider;
private Provider<A4> provideA4Provider;
private MembersInjector<DaggerActivity> daggerActivityMembersInjector;
private DaggerA2Component(DaggerA2Component.Builder builder) {
assert builder != null;
this.initialize(builder);
}
public static DaggerA2Component.Builder builder() {
return new DaggerA2Component.Builder();
}
public static A2Component create() {
return builder().build();
}
private void initialize(DaggerA2Component.Builder builder) {
this.povideAZhangSanProvider = A2Module_PovideAZhangSanFactory.create(builder.a2Module);
this.povideALisiProvider = A2Module_PovideALisiFactory.create(builder.a2Module);
this.provideA3Provider = A2Module_ProvideA3Factory.create(builder.a2Module);
this.provideA4Provider = ScopedProvider.create(A2Module_ProvideA4Factory.create(builder.a2Module));
this.daggerActivityMembersInjector = DaggerActivity_MembersInjector.create(MembersInjectors.noOp(), this.povideAZhangSanProvider, this.povideALisiProvider, this.provideA3Provider, this.provideA4Provider);
}
public void inject(DaggerActivity mainActivity) {
this.daggerActivityMembersInjector.injectMembers(mainActivity);
}
}
可以看到对于A2Module里的四个被@Provides注解的方法,DaggerA2Component生成了四个Provider对象,
private Provider<A2> povideAZhangSanProvider;
private Provider<A2> povideALisiProvider;
private Provider<A3> provideA3Provider;
private Provider<A4> provideA4Provider;
而这四个对象的创建时重点 ,在initialize()方法中,可以发现前三个对象的创建都是xx_Factory.create()方式,而使用@PerActivity注解的provideA4Provider则是ScopedProvider.create()创建,区别就在这里了,Factory工厂模式创建的对象每次都是新建的对象,而ScopedProvider则可以返回上次创建的对象,起到了单例的作用。
具体可看ScopedProvider类
public final class ScopedProvider<T> implements Provider<T> {
private static final Object UNINITIALIZED = new Object();
private final Factory<T> factory;
private volatile Object instance = UNINITIALIZED;
private ScopedProvider(Factory<T> factory) {
assert factory != null;
this.factory = factory;
}
@SuppressWarnings("unchecked") // cast only happens when result comes from the factory
@Override
public T get() {
// double-check idiom from EJ2: Item 71
Object result = instance;
if (result == UNINITIALIZED) {
synchronized (this) {
result = instance;
if (result == UNINITIALIZED) {
instance = result = factory.get();
}
}
}
return (T) result;
}
/** Returns a new scoped provider for the given factory. */
public static <T> Provider<T> create(Factory<T> factory) {
if (factory == null) {
throw new NullPointerException();
}
return new ScopedProvider<T>(factory);
}
}
可以看到 T get()方法取A4对象时,使用了单例方法,如果已被创建则直接返回。
子Component
子Component跟前面的一个Component依赖另一个Component有点像,区别是子Component可以获取到父Component的所有可以生产出的对象,而Component依赖则只能获取到被依赖的Component所暴露出来的可以生产的对象。
A4 类:
public class A4 {
@Inject
public A4() {
}
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
@Component(dependencies = AComponent.class, modules = A2Module.class)
public interface A2Component {
void inject(DaggerActivity mainActivity);
A4Component plus(A4Module module1); // //参数为A4Component依赖的Module
}
@Subcomponent(modules = A4Module.class)
public interface A4Component {
void inject(DaggerActivity mainActivity);
}
DaggerActivity
public class DaggerActivity extends Activity {
private static final String TAG = "DaggerActivity";
@Inject
A2 aaa2;
@Inject
A4 aaa4;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DaggerA2Component.builder()
.a2Module(new A2Module())
.build()
.plus(new A4Module())
.inject(this);
aaa2.setAge(20);
aaa2.getAge();
Log.d(TAG, "onCreate --> aaa2.getAge() : : " + aaa2.getAge());
aaa4.setAge(30);
aaa4.getAge();
Log.d(TAG, "onCreate --> aaa4.getAge() : : " + aaa4.getAge());
Log.d(TAG, "onCreate ------------------------------------------> : ");
}
}
可以看到 A4在这里也可以正常使用。
@Named注解
这个注解是用来设置别名的,用来区分同一个类型的不同对象。比如我们都知道Android 中的Context有两种,一种是全局的,一种是Activity中的,为了区分他们,我们就可以加上别名;又比如有一个Person类,他有两个实例,一个是张三,一个是李四,我们也可以用别名区分他们。
A2 类 :
public class A2 {
public A2(int age) {
this.age = age;
}
public A2() {
}
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
A2Module :
@Module
public class A2Module {
@Named("李四")
@Provides
A2 povideA2() {
return new A2(21);
}
@Named("张三")
@Provides
A2 povideA21() {
return new A2(25);
}
}
使用 :
public class DaggerActivity extends Activity {
private static final String TAG = "DaggerActivity";
@Named("张三")
@Inject
A2 aaa2;
@Named("李四")
@Inject
A2 aaa2_lisi;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DaggerA2Component.builder()
.a2Module(new A2Module())
.build()
.inject(this);
Log.d(TAG, "onCreate --> aaa2.getAge() : : " + aaa2.getAge());
Log.d(TAG, "onCreate --> aaa2_lisi.getAge() : : " + aaa2_lisi.getAge());
}
}
大体就写到这里了 。。。。
参考文档 :
http://www.2cto.com/kf/201604/499397.html
http://www.cnblogs.com/zhuyp1015/p/5119727.html
http://blog.csdn.net/duo2005duo/article/details/50696166
http://www.cnblogs.com/tiantianbyconan/archive/2016/01/02/5095426.html