想学习下Dagger2 ,搜了不少资料但都是附带着RxJava等其余东西,让楼主学习起来比较费时(可能比较笨),本人也没有使用过Dagger1.x,因此学习Dagger2的更是举步维艰啊。 html
看了不少资料,终于懂了一点,下面主要说说Dagger2的使用过程及本身看法,加深印象。说的不对的也请读者指正。android
Dagger2是Android的一个依赖注入框架,可用于模块间解耦,提升代码的健壮性和可维护性。app
Dagger2是基于一个有向无环图结构的依赖注入库,所以dagger2的使用过程当中不能出现循环依赖的现象。框架
如下都已 Android studio开发工具为例。ide
在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 添加gradle
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
如:
buildscript { repositories { jcenter() } dependencies { classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4' } }
apt相关的依赖必定要加上,要不生成不了对应所需文件 Dagger+"" 等。
Dagger2 经过注解来工做,定义不一样的角色,主要的注解包括:@Component 、@Module 、@Inject、@Provides 、@Scope 、@SubComponent 等。
Component和Module是Dagger2的两个主要注解。
module是生产对象的地方,便是生产方,须要什么样的对象都要在这里生产
Component 是联系module和module使用场景的桥梁,module生产的对象须要在哪里使用要靠Component来提供、暴露,即提供方。使module和module的使用场景达到了一个解耦。
模拟一个场景,类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注解是否是能够不要了呢 ?
通常系统的 、SDK的、第三方库提供的对象用Module (你无法在人家的构造函数上添加@Inject啊)
自定义的对象用Inject 定义一个子类继承系统、SDK、第三方库的对象,这时也可使用Inject。
依赖一个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。
这个注解是用来划分做用域的(在哪儿使用,使用范围),意思是画出一块区域来,生产的东西若是限定在此做用域,那都放到这里,做用域的场景类(如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); } }
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所暴露出来的能够生产的对象。
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在这里也能够正常使用。
这个注解是用来设置别名的,用来区分同一个类型的不一样对象。好比咱们都知道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