Hi~ 我是Dagger2
Dagger2是个什么东西
1.主要功能是依赖注入。
2.在编译时进行依赖注入的框架,而不是通过反射的方式注入。
3.原来有square维护,现在由google维护。为了区分就叫dagger2。
项目地址
https://github.com/google/dagger
文档
https://google.github.io/dagger/
API描述
https://google.github.io/dagger/api/2.0/
使用Dagger2的好处
- 解耦合,可以用注入的方式注入依赖对象。
- 方便测试。
基本概念
注解
注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
可以参考我是陆大旭的GitBook-Android-注解
依赖注入
当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。
可以通过以下几种方式实现
- 通过接口注入
- 通过set方法注入
- 通过构造方法注入
- 通过Java注解注入
Dagger2就是通过最右一种方法“Java注解注入”完成依赖注入。
如何引入Dagger2
在build.gradle(Project:xxx)中添加如下代码
dependencies
{
classpath 'com.android.tools.build:gradle:2.3.2'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
在build.gradle(Module:app)中添加如下代码
apply plugin: 'com.android.application'
apply plugin: 'android-apt'
......
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
/**
* dragger2
*/
//使用APT生成工具,生成需要的DI代码
apt 'com.google.dagger:dagger-compiler:2.5'
//JSR250的jar包,使用这个和使用glassFish的那个一样,仅为了使用@Inject 和@Named注解
// provided 'javax.annotation:jsr250-api:1.0'
//Dagger2 的依赖
compile 'com.google.dagger:dagger:2.5'
}
几个基本概念
@Inject
此注解用于标记构造函数、方法和字段,也可能使用于静态实例成员。可注解成员可以是任意修饰符(private,package-private,protected,public)。注入顺序:构造函数、字段,然后是方法。父类的字段和方法注入优先于子类的字段和方法,同一类中的字段和方法是没有顺序的。
@Module
此注解用于标记类,Modules类里面的方法专门提供依赖, 在构造类的实例的时候,就知道从哪里去找到需要的依赖。
@Provides
此注解用于标记方法,表示可以通过这个方法获取一个对象,一般用于自定义类中。
@Component
此注解用于标记接口,标示一个注入器。是@Inject和@Module的桥梁,它的主要作用就是连接这两个部分。
简单的例子
代码例子
https://github.com/iamludaxu/ae/tree/master/app/src/main/java/gift/witch/android/ae/dagger2
- 第一步:编写一个Module(FirstModule.class),类需要@Module注解来标识。
Module是提供生成依赖对象的。provideName()提供了一个String对象。注意不能用private修饰。
FirstModule.class
@Module
public class FirstModule {
private String mName;
public FirstModule(String name){
mName = name;
}
@Provides
public String provideName(){
return mName;
}
}
- 第二步:编写一个Component(FirstComponent.class),接口需要@Component注解来标识。
Component注解中需要声明modules(FirstModule.class)
FirstComponent.class
@Component(modules = FirstModule.class)
public interface FirstComponent {
void inject(Dagger2Activity activity);
}
- 第三步:编写一个目标类(FirstTargetClass.class),其构造方法@ Inject注解进行标识,表明是一个依赖的构造函数。
FirstTargetClass.class
public class FirstTargetClass {
private String mName;
@Inject
public FirstTargetClass(String name){
mName = name;
}
public String getName(){
return mName;
}
}
- 第四步:使用Dagger进行注入,在Activity中声明一个FirstTargetClass对象,用@Inject注释进行注解。然后调用DaggerXXXXX(DaggerFirstComponent)进行注入。
Dagger2Activity.class
public class Dagger2Activity extends BaseCompatActivity {
@Inject
FirstTargetClass mFirstTargetClass;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dagger2);
DaggerFirstComponent.builder().firstModule(new FirstModule("name")).build().inject(this);
}
}
分析一下代码
四个数据对象
InjectConstructionData.class
/**
* 在构建函数中注入的对象
*/
public class InjectConstructionData {
private String mTag;
public InjectConstructionData() {
mTag = "InjectConstructionData";
}
public String getTag() {
return mTag;
}
}
InjectMethodData.class
/**
* 在方法中注入的对象
*/
public class InjectMethodData {
private String mTag;
public InjectMethodData() {
mTag = "InjectMethodData";
}
public String getTag() {
return mTag;
}
}
InjectPropertyData.class
/**
* 在属性中注入的对象
*/
public class InjectPropertyData {
private String mTag;
public InjectPropertyData(){
mTag = "InjectMemberData";
}
public String getTag(){
return mTag;
}
}
TestData.class
/**
* 测试数据
*/
public class TestData {
private String mName;
public TestData(String name){
mName = name;
}
public String getName(){
return mName;
}
}
FirstModule.class
/**
* 第一个Module
*/
@Module
public class FirstModule {
private String mName;
public FirstModule(String name){
mName = name;
}
/**
* 提供String对象
* @return
*/
@Provides
public String provideName(){
return mName;
}
/**
* 提供InjectMethodData对象
* @return
*/
@Provides
public InjectMethodData provideInjectMemberData(){
return new InjectMethodData();
}
/**
* 提供InjectConstructionData对象
* @return
*/
@Provides
public InjectConstructionData provideInjectConstructionData(){
return new InjectConstructionData();
}
/**
* 提供InjectPropertyData对象
* @return
*/
@Provides
public InjectPropertyData provideInjectPropertyData(){
return new InjectPropertyData();
}
}
SecondModule.class
/**
* 第二个Module
*/
@Module
public class SecondModule {
private TestData mTestData;
public SecondModule(){
mTestData = new TestData("new SecondModule().TestData()");
}
/**
* 提供TestData对象
* @return
*/
@Provides
TestData providesTestData(){
return mTestData;
}
}
FirstTargetClass.class
/**
*
* 目标类,需要注入各种对象
*
*/
public class FirstTargetClass {
private InjectConstructionData mInjectConstructionData;
@Inject
InjectPropertyData mInjectPropertyData;
@Inject
TestData mTestData;
private InjectMethodData mInjectMethodData;
@Inject
public FirstTargetClass(InjectConstructionData injectConstructionData){
mInjectConstructionData = injectConstructionData;
}
@Inject
public void set(InjectMethodData injectMethodData){
mInjectMethodData = injectMethodData;
}
public InjectConstructionData getInjectConstructionData(){
return mInjectConstructionData;
}
}
FirstComponent.class
/**
* Dagger2中的Component向Dagger2Activity中的类注入对象实例
*/
@Component(modules = {FirstModule.class,SecondModule.class})
public interface FirstComponent {
void inject(Dagger2Activity activity);
}
在build后就会生成DaggerFirstComponent和FirstModule_ProvideInjectPropertyDataFactory、SecondModule_ProvidesTestDataFactory等工厂类。
Dagger2Activity.class
public class Dagger2Activity extends BaseCompatActivity {
@Inject
FirstTargetClass mFirstTargetClass;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dagger2);
DaggerFirstComponent.builder()
.firstModule(new FirstModule("name"))
.secondModule(new SecondModule())
.build()
.inject(this);
}
}
DaggerFirstComponent.class
public final class DaggerFirstComponent implements FirstComponent {
private Provider provideInjectPropertyDataProvider;
private Provider providesTestDataProvider;
private Provider provideInjectMemberDataProvider;
private MembersInjector firstTargetClassMembersInjector;
private Provider provideInjectConstructionDataProvider;
private Provider firstTargetClassProvider;
private MembersInjector dagger2ActivityMembersInjector;
private DaggerFirstComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.provideInjectPropertyDataProvider =
FirstModule_ProvideInjectPropertyDataFactory.create(builder.firstModule);
this.providesTestDataProvider =
SecondModule_ProvidesTestDataFactory.create(builder.secondModule);
this.provideInjectMemberDataProvider =
FirstModule_ProvideInjectMemberDataFactory.create(builder.firstModule);
this.firstTargetClassMembersInjector =
FirstTargetClass_MembersInjector.create(
provideInjectPropertyDataProvider,
providesTestDataProvider,
provideInjectMemberDataProvider);
this.provideInjectConstructionDataProvider =
FirstModule_ProvideInjectConstructionDataFactory.create(builder.firstModule);
this.firstTargetClassProvider =
FirstTargetClass_Factory.create(
firstTargetClassMembersInjector, provideInjectConstructionDataProvider);
this.dagger2ActivityMembersInjector =
Dagger2Activity_MembersInjector.create(firstTargetClassProvider);
}
@Override
public void inject(Dagger2Activity activity) {
dagger2ActivityMembersInjector.injectMembers(activity);
}
public static final class Builder {
private FirstModule firstModule;
private SecondModule secondModule;
private Builder() {}
public FirstComponent build() {
if (firstModule == null) {
throw new IllegalStateException(FirstModule.class.getCanonicalName() + " must be set");
}
if (secondModule == null) {
this.secondModule = new SecondModule();
}
return new DaggerFirstComponent(this);
}
public Builder firstModule(FirstModule firstModule) {
this.firstModule = Preconditions.checkNotNull(firstModule);
return this;
}
public Builder secondModule(SecondModule secondModule) {
this.secondModule = Preconditions.checkNotNull(secondModule);
return this;
}
}
}
解释一下
- 提供对象实例的XXXProvider工厂类,都继承至Factory
,而Factory 又继承Provider ,在Provider 中有个get()方法就是获取对象实例用的。
比如FirstModule_ProvideInjectPropertyDataFactory.class
当调用get()方法的时候其实就是调用FirstModule中的provideInjectPropertyData()方法。
public final class FirstModule_ProvideInjectPropertyDataFactory
implements Factory {
private final FirstModule module;
public FirstModule_ProvideInjectPropertyDataFactory(FirstModule module) {
assert module != null;
this.module = module;
}
@Override
public InjectPropertyData get() {
return Preconditions.checkNotNull(
module.provideInjectPropertyData(),
"Cannot return null from a non-@Nullable @Provides method");
}
public static Factory create(FirstModule module) {
return new FirstModule_ProvideInjectPropertyDataFactory(module);
}
}
- 注入实例的XXXMembersInjector类,继承至MembersInjector
,注入的工作都在injectMembers()方法中实现。
比如FirstTargetClass_MembersInjector.class
注入的时候会先获得需要注入的工厂类,然后通过调用injectMembers()方法进行注入。
public final class FirstTargetClass_MembersInjector implements MembersInjector {
private final Provider mInjectPropertyDataProvider;
private final Provider mTestDataProvider;
private final Provider injectMethodDataProvider;
public FirstTargetClass_MembersInjector(
Provider mInjectPropertyDataProvider,
Provider mTestDataProvider,
Provider injectMethodDataProvider) {
assert mInjectPropertyDataProvider != null;
this.mInjectPropertyDataProvider = mInjectPropertyDataProvider;
assert mTestDataProvider != null;
this.mTestDataProvider = mTestDataProvider;
assert injectMethodDataProvider != null;
this.injectMethodDataProvider = injectMethodDataProvider;
}
public static MembersInjector create(
Provider mInjectPropertyDataProvider,
Provider mTestDataProvider,
Provider injectMethodDataProvider) {
return new FirstTargetClass_MembersInjector(
mInjectPropertyDataProvider, mTestDataProvider, injectMethodDataProvider);
}
@Override
public void injectMembers(FirstTargetClass instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.mInjectPropertyData = mInjectPropertyDataProvider.get();
instance.mTestData = mTestDataProvider.get();
instance.set(injectMethodDataProvider.get());
}
public static void injectMInjectPropertyData(
FirstTargetClass instance, Provider mInjectPropertyDataProvider) {
instance.mInjectPropertyData = mInjectPropertyDataProvider.get();
}
public static void injectMTestData(
FirstTargetClass instance, Provider mTestDataProvider) {
instance.mTestData = mTestDataProvider.get();
}
}
- 至于在injectMembers()方法哪里调用的请看FirstTargetClass_Factory.class中的get()方法。injectMembers就是将目标类FirstTargetClass注入依赖对象并返回对象的实例。
public final class FirstTargetClass_Factory implements Factory {
private final MembersInjector firstTargetClassMembersInjector;
private final Provider injectConstructionDataProvider;
public FirstTargetClass_Factory(
MembersInjector firstTargetClassMembersInjector,
Provider injectConstructionDataProvider) {
assert firstTargetClassMembersInjector != null;
this.firstTargetClassMembersInjector = firstTargetClassMembersInjector;
assert injectConstructionDataProvider != null;
this.injectConstructionDataProvider = injectConstructionDataProvider;
}
@Override
public FirstTargetClass get() {
return MembersInjectors.injectMembers(
firstTargetClassMembersInjector,
new FirstTargetClass(injectConstructionDataProvider.get()));
}
public static Factory create(
MembersInjector firstTargetClassMembersInjector,
Provider injectConstructionDataProvider) {
return new FirstTargetClass_Factory(
firstTargetClassMembersInjector, injectConstructionDataProvider);
}
}
- 最后通过DaggerXXX.inject()将对象实例注入到要用的地方。
在Dagger2Activity.class中mFirstTargetClass就是要注入的对象。
@Inject
FirstTargetClass mFirstTargetClass;
- 然后通过下面的方式设置FirstModule和SecondModule,并调用inject()方法。
DaggerFirstComponent.builder()
.firstModule(new FirstModule("name"))
.secondModule(new SecondModule())
.build()
.inject(this);
- 这样就会调用dagger2ActivityMembersInjector.injectMembers()向Dagger2Activity中注入了FirstTargetClass。
@Override
public void inject(Dagger2Activity activity) {
dagger2ActivityMembersInjector.injectMembers(activity);
}
多看多理解
其他技术点
单例(Singleton)
在Component中增加Singleton注释
SingletonComponent.class
@Singleton
@Component(modules = SingleModule.class)
public interface SingletonComponent {
void inject(SingleTest singleTest);
}
SingleModule.class的方法中增加@Singleton注释
@Module
public class SingleModule {
private int i = 0;
public SingleModule(){
}
@Singleton
@Provides
TestData provideSingleTestData(){
i++;
return new TestData("name"+i);
}
}
SingleTest.class
/**
* 单例目标类
*/
public class SingleTest {
@Inject
TestData mTestData1;
@Inject
TestData mTestData2;
SingleTest(){
DaggerSingletonComponent.builder().singleModule(new SingleModule()).build().inject(this);
}
public void print(){
Logger.i(mTestData1.toString());
Logger.i(mTestData2.toString());
Logger.i(mTestData1.getName());
Logger.i(mTestData2.getName());
}
}
生成的DaggerSingletonComponent.class
public final class DaggerSingletonComponent implements SingletonComponent {
private Provider provideSingleTestDataProvider;
......
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.provideSingleTestDataProvider =
DoubleCheck.provider(SingleModule_ProvideSingleTestDataFactory.create(builder.singleModule));
this.singleTestMembersInjector =
SingleTest_MembersInjector.create(provideSingleTestDataProvider); }
......
}
看看看看看这里多了一个里多了一个DoubleCheck.provider()
public final class DoubleCheck implements Provider, Lazy {
private static final Object UNINITIALIZED = new Object();
private volatile Provider provider;
private volatile Object instance = UNINITIALIZED;
private DoubleCheck(Provider provider) {
assert provider != null;
this.provider = provider;
}
@SuppressWarnings("unchecked") // cast only happens when result comes from the provider
@Override
public T get() {
Object result = instance;
if (result == UNINITIALIZED) {
synchronized (this) {
result = instance;
if (result == UNINITIALIZED) {
result = provider.get();
/* Get the current instance and test to see if the call to provider.get() has resulted
* in a recursive call. If it returns the same instance, we'll allow it, but if the
* instances differ, throw. */
Object currentInstance = instance;
if (currentInstance != UNINITIALIZED && currentInstance != result) {
throw new IllegalStateException("Scoped provider was invoked recursively returning "
+ "different results: " + currentInstance + " & " + result);
}
instance = result;
/* Null out the reference to the provider. We are never going to need it again, so we
* can make it eligible for GC. */
provider = null;
}
}
}
return (T) result;
}
/** Returns a {@link Provider} that caches the value from the given delegate provider. */
public static Provider provider(Provider delegate) {
checkNotNull(delegate);
if (delegate instanceof DoubleCheck) {
/* This should be a rare case, but if we have a scoped @Binds that delegates to a scoped
* binding, we shouldn't cache the value again. */
return delegate;
}
return new DoubleCheck(delegate);
}
/** Returns a {@link Lazy} that caches the value from the given provider. */
public static Lazy lazy(Provider provider) {
if (provider instanceof Lazy) {
@SuppressWarnings("unchecked")
final Lazy lazy = (Lazy) provider;
// Avoids memoizing a value that is already memoized.
// NOTE: There is a pathological case where Provider may implement Lazy, but P and L
// are different types using covariant return on get(). Right now this is used with
// DoubleCheck exclusively, which is implemented such that P and L are always
// the same, so it will be fine for that case.
return lazy;
}
return new DoubleCheck(checkNotNull(provider));
}
}
这里会调用一个DoubleCheck
在Component中需要加@Singleton,否则就会报xxxx(unscoped) may not reference scoped bindings的错。
作用域(Scope)
用来给依赖划定作用域
定义一个作用域CustomScope
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomScope {
}
CustomModule.class
@Module
public class CustomModule {
private TestData mTestData;
public CustomModule(String name) {
mTestData = new TestData(name);
}
@CustomScope
@Provides
public TestData provideTestData() {
return mTestData;
}
}
CustomComponent.class
@CustomScope
@Component(modules = CustomModule.class)
public interface CustomComponent {
void inject(CustomTest customTest);
void inject(CustomOtherTest customOtherTest);
}
CustomTest.class
public class CustomTest {
@Inject
TestData mTestData;
public CustomTest(){
DaggerCustomComponent.builder().customModule(new CustomModule("CustomTest NAME")).build().inject(this);
}
public void print(){
Logger.i(mTestData.toString());
}
}
CustomOtherTest.class
public class CustomOtherTest {
@Inject
TestData mTestData;
public CustomOtherTest(){
DaggerCustomComponent.builder().customModule(new CustomModule("CustomTest NAME")).build().inject(this);
}
public void print(){
Logger.i(mTestData.toString());
}
}
Dagger2Activity.class
public class Dagger2Activity extends BaseCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
......
CustomTest customTest = new CustomTest();
customTest.print();//gift.witch.android.ae.dagger2.TestData@42353bc8
CustomOtherTest customOtherTest = new CustomOtherTest();
customOtherTest.print();//gift.witch.android.ae.dagger2.TestData@423567b8
}
}
打印结果...额...不同实例,这个“作用域”作用好像没有任何作用啊!
来我们回头再看看DaggerCustomComponent.class。里面还是多了一个DoubleCheck.provider()方法,和@Singleton注解效果一样。那不是应该是单例的效果吗????
好吧,这个@Singleton是不能实现单例的。实现单例的是XXXComponent被实例化一次,这个才是关键的点。
具体的请参考“Dagger2 使用正确姿势。”
限定符(Qualifier)
当一个类的类型不足以标示一个依赖的时候,我们就可以用这个注解。
/**
* 自定义限定符
*/
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface QualifierType {
String value() default "";
}
QualifierModule.class
@Module
public class QualifierModule {
@QualifierType("A")
@Provides
TestData provideA(){
return new TestData("A");
}
@QualifierType("B")
@Provides
TestData provideB(){
return new TestData("B");
}
}
QualifierComponent.class
@Component(modules = QualifierModule.class)
public interface QualifierComponent {
void inject(QualifierTest qualifierTest);
@QualifierType("A")
TestData provideA();
@QualifierType("B")
TestData provideB();
}
QualifierTest.class
public class QualifierTest {
@QualifierType("A")
@Inject
TestData mTestDataA;
@QualifierType("B")
@Inject
TestData mTestDataB;
public QualifierTest(){
QualifierComponent component = DaggerQualifierComponent.builder().qualifierModule(new QualifierModule()).build();
component.inject(this);
TestData testDataA = component.provideA();
TestData testDataB = component.provideB();
}
public void print(){
Logger.i("TestDataA:"+mTestDataA.getName());
Logger.i("TestDataB:"+mTestDataB.getName());
}
}
Dagger2Activity.class
public class Dagger2Activity extends BaseCompatActivity {
@Inject
FirstTargetClass mFirstTargetClass;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dagger2);
......
QualifierTest qualifierTest = new QualifierTest();
qualifierTest.print();//TestDataA:A TestDataB:B
}
}
这里就分别打印出“TestDataA:A TestDataB:B”
- 如果在QualifierModule.class中去掉QualifierType注释那么在编译的时候就会报“is bound multiple times”的错误。
- 默认和用@Named注释来做限定符。
懒加载(Lazy)
LzayModule.class
@Module
public class LzayModule {
@Provides
public TestData provideTestData(){
return new TestData("LzayModule TestData");
}
}
LazyComponent.class
@Component(modules = LzayModule.class)
public interface LazyComponent {
void inject(LazyTest lazyTest);
}
LazyTest.class
public class LazyTest {
@Inject
Lazy mLazy_TestData;
@Inject
Provider mProvides_TestData;
public LazyTest(){
DaggerLazyComponent.builder().lzayModule(new LzayModule()).build().inject(this);
}
public void print(){
Logger.i("TestData one:"+mLazy_TestData.get().toString());//TestData one:gift.witch.android.ae.dagger2.TestData@423ab570
Logger.i("TestData two:"+mLazy_TestData.get().toString());//TestData two:gift.witch.android.ae.dagger2.TestData@423ab570
Logger.i("TestData one:"+mProvides_TestData.get().toString());//TestData one:gift.witch.android.ae.dagger2.TestData@423af620
Logger.i("TestData two:"+mProvides_TestData.get().toString());//TestData two:gift.witch.android.ae.dagger2.TestData@423b1628
}
}
Dagger2Activity.class
public class Dagger2Activity extends BaseCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dagger2);
......
LazyTest lazyTest = new LazyTest();
lazyTest.print();
}
}
看打印的结果怎么就像@Singleton一样,Lazy
public final class LazyTest_MembersInjector implements MembersInjector {
private final Provider mProvides_TestDataAndMLazy_TestDataProvider;
public LazyTest_MembersInjector(Provider mProvides_TestDataAndMLazy_TestDataProvider) {
assert mProvides_TestDataAndMLazy_TestDataProvider != null;
this.mProvides_TestDataAndMLazy_TestDataProvider = mProvides_TestDataAndMLazy_TestDataProvider;
}
public static MembersInjector create(
Provider mProvides_TestDataAndMLazy_TestDataProvider) {
return new LazyTest_MembersInjector(mProvides_TestDataAndMLazy_TestDataProvider);
}
@Override
public void injectMembers(LazyTest instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.mLazy_TestData = DoubleCheck.lazy(mProvides_TestDataAndMLazy_TestDataProvider);
instance.mProvides_TestData = mProvides_TestDataAndMLazy_TestDataProvider;
}
public static void injectMLazy_TestData(
LazyTest instance, Provider mLazy_TestDataProvider) {
instance.mLazy_TestData = DoubleCheck.lazy(mLazy_TestDataProvider);
}
public static void injectMProvides_TestData(
LazyTest instance, Provider mProvides_TestData) {
instance.mProvides_TestData = mProvides_TestData;
}
}
干货文章
- Dagger2 入门,以初学者角度
- 神兵利器Dagger2
- DI框架Dagger2系统性学习-不容错过的干货
- Google官方MVP+Dagger2架构详解【从零开始搭建android框架系列(6)】
应用例子
- Google MVP Dagger2
- MVPArms Dagger2+Rxjava+Retrofit
我叫陆大旭。
一个懂点心理学的无聊程序员大叔。
看完文章无论有没有收获,记得打赏、关注和点赞!