Dagger 2 在 Android 上的使用(二)
本文介绍了Dagger 2 中@Inject、@Component、@Module和@Provides以及@Module和@Binds的使用。
本文首发:http://yuweiguocn.github.io/
《七步诗》
煮豆燃豆萁,豆在釜中泣。
本是同根生,相煎何太急?
-两汉,曹植
前言
Dagger 2 在 Android 上的使用(一)
Dagger 2 在 Android 上的使用(二)
Dagger 2 在 Android 上的使用(三)
Dagger 2 在 Android 上的使用(四)
Dagger 2 在 Android 上的使用(五)
Dagger 2 在 Android 上的使用(六)
在上一篇文章中我们介绍了Dagger2在android上的简单用法,接下来我们对Dagger2中提供的注解进行详细的使用说明。
注解@Inject和注解@Component
使用注解@Inject
和注解@Component
可以完成简单依赖注入。
先来看一个未使用Dagger2的例子,稍候使用Dagger2完成依赖注入。
public class People { public String doWhat() { return "eat"; }}
在Activity中实例化此类并调用相应方法:
public class PeopleActivity extends Activity { private People people; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); people=new People(); Log.d("debug", people.doWhat()); }}
使用Dagger2完成依赖注入,People类需要添加一个空的构造方法并使用@Inject
进行注解:
public class People { @Inject public People() { } public String doWhat() { return "eat"; }}
注解@Inject
用在构造方法上表示告诉Dagger 2可以使用此构造方法提供需要的实例。
添加一个@Component
注解的接口类,这会生成以Dagger为前缀的Component实现类。必须包含至少一个抽象方法。下面的示例是一个成员注入方法,成员注入方法有一个参数,将依赖注入到实例的所有被注入注解的字段和方法中。返回值可以为void或方法的参数类型方便链式调用。注解@Component
只能用在接口或抽象类上。
@Componentpublic interface PeopleComponent { void inject(PeopleActivity activity);}
在Activity中使用@Inject
对People进行注解,注意类型不能是private的。然后编译使用生成的DaggerPeopleComponent类进行依赖注入。
public class PeopleActivity extends Activity{ @Inject People people; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerPeopleComponent.create().inject(this); Log.d("debug", people.doWhat()); }}
然后我们看一下生成的类是如何实现依赖注入的。在Activity中的成员变量people添加的@Inject
注解生成了对应的MembersInjector类,用于给对应注入成员变量赋值。
public final class PeopleActivity_MembersInjector implements MembersInjector { private final Provider peopleProvider; public PeopleActivity_MembersInjector(Provider peopleProvider) { this.peopleProvider = peopleProvider; } public static MembersInjector create(Provider peopleProvider) { return new PeopleActivity_MembersInjector(peopleProvider); } @Override public void injectMembers(PeopleActivity instance) { injectPeople(instance, peopleProvider.get()); } public static void injectPeople(PeopleActivity instance, People people) { instance.people = people; //完成赋值 }}
定义的Component接口类生成了对应的实现类,当我们在Activity中调用inject方法时完成了成员变量的赋值。
public final class DaggerPeopleComponent implements PeopleComponent { private DaggerPeopleComponent(Builder builder) {} public static Builder builder() { return new Builder(); } public static PeopleComponent create() { return new Builder().build(); } @Override public void inject(PeopleActivity activity) { injectPeopleActivity(activity); } private PeopleActivity injectPeopleActivity(PeopleActivity instance) { PeopleActivity_MembersInjector.injectPeople(instance, new People()); //进行成员变量的注入 return instance; } public static final class Builder { private Builder() {} public PeopleComponent build() { return new DaggerPeopleComponent(this); } }}
PS:从生成的代码中我们发现了一个People_Factory类用于People的实例化,但目前并没有用到。
这样我们使用注解@Inject
和注解@Component
就完成了简单的依赖注入。
注解@Inject
是JSR-330标准中的一部分,标记那些应该被依赖注入框架提供的依赖。
注解@Inject
用在构造器上有两种作用:
- 表示可以使用此构造器构建对象
- 注入构造器所需要的参数的依赖
例如People依赖Tools类,这样也会完成Tools的注入。
public class People { private Tools tools; @Inject public People(Tools tools) { this.tools = tools; }}public class Tools { @Inject public Tools() { } public String getCar() { return "car"; }}
注解@Inject
可以用在成员变量完成依赖注入,正如上面看到的例子,也可以用在成员方法上完成依赖注入,例如:
public class PeopleActivity extends Activity{ private People people; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerPeopleComponent.create().inject(this); Log.d("debug", people.doWhat()); } @Inject public void setPeople(People people) { this.people = people; }}
然后我们再来看一下生成的代码:
public final class DaggerPeopleComponent implements PeopleComponent { private DaggerPeopleComponent(Builder builder) {} ... private People getPeople() { return new People(new Tools()); } @Override public void inject(PeopleActivity activity) { injectPeopleActivity(activity); } private PeopleActivity injectPeopleActivity(PeopleActivity instance) { PeopleActivity_MembersInjector.injectSetPeople(instance, getPeople()); return instance; } ...}
成员注入:
public final class PeopleActivity_MembersInjector implements MembersInjector { ... public static void injectSetPeople(PeopleActivity instance, People people) { instance.setPeople(people); }}
从生成的代码来看使用成员变量注入和成员方法注入基本没有任何区别,这两者都是在调用注入方法时完成变量的赋值。推荐大家使用更简单的成员变量注入方法。
注解@Module和注解@Provides
使用@Inject标注构造方法这种方式会有以下限制:
- 第三方库无法注入
- 接口和抽象类无法注入
针对上述限制我们可以使用注解@Module
和注解@Provides
完成注入,接下来看一个抽象类和接口注入的实例:
public abstract class People { abstract String doWhat();}public class Student extends People { @Override String doWhat() { return "study"; }}public class Worker extends People { @Override String doWhat() { return "work"; }}
新建Module类用于提供相应实例:
@Modulepublic class PeopleModule { @Provides People providePeople() { //为抽象类提供实例 return new Student(); } @Provides PeopleContract.Presenter providePeoplePresenter(){ //为接口提供实例 return new PeoplePresenter(); }}
在Component类指定Module类:
@Component(modules = PeopleModule.class)public interface PeopleComponent { void inject(PeopleActivity activity);}
在Activity中进行注入:
public class PeopleActivity extends Activity{ @Inject People people; //抽象类的注入 @Inject PeopleContract.Presenter mPresenter; //接口的注入 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerPeopleComponent.create().inject(this); L.d(people.doWhat()); mPresenter.takeView(this); }}
注意对于可能为null
的实例需要在提供实例的方法上和注入实例的变量上添加@Nullable
注解。
Dagger2自动生成的类,用于提供People实例:
public final class PeopleModule_ProvidePeopleFactory implements Factory { private final PeopleModule module; public PeopleModule_ProvidePeopleFactory(PeopleModule module) { this.module = module; } @Override public People get() { return provideInstance(module); } public static People provideInstance(PeopleModule module) { return proxyProvidePeople(module); } public static PeopleModule_ProvidePeopleFactory create(PeopleModule module) { return new PeopleModule_ProvidePeopleFactory(module); } public static People proxyProvidePeople(PeopleModule instance) { // 提供People的实例 return Preconditions.checkNotNull( instance.providePeople(), "Cannot return null from a non-@Nullable @Provides method"); }}
Dagger2自动生成的类,用于提供PeopleContract.Presenter实例:
public final class PeopleModule_ProvidePeoplePresenterFactory implements Factory { private final PeopleModule module; public PeopleModule_ProvidePeoplePresenterFactory(PeopleModule module) { this.module = module; } @Override public PeopleContract.Presenter get() { return provideInstance(module); } public static PeopleContract.Presenter provideInstance(PeopleModule module) { return proxyProvidePeoplePresenter(module); } public static PeopleModule_ProvidePeoplePresenterFactory create(PeopleModule module) { return new PeopleModule_ProvidePeoplePresenterFactory(module); } public static PeopleContract.Presenter proxyProvidePeoplePresenter(PeopleModule instance) { return Preconditions.checkNotNull( instance.providePeoplePresenter(), //提供PeopleContract.Presenter实例 "Cannot return null from a non-@Nullable @Provides method"); }}
在Component类中进行了调用:
public final class DaggerPeopleComponent implements PeopleComponent { private PeopleModule peopleModule; private DaggerPeopleComponent(Builder builder) { initialize(builder); } public static Builder builder() { return new Builder(); } public static PeopleComponent create() { return new Builder().build(); } @SuppressWarnings("unchecked") private void initialize(final Builder builder) { this.peopleModule = builder.peopleModule; } @Override public void inject(PeopleActivity activity) { injectPeopleActivity(activity); } private PeopleActivity injectPeopleActivity(PeopleActivity instance) {//完成成员变量的注入 PeopleActivity_MembersInjector.injectPeople( instance, PeopleModule_ProvidePeopleFactory.proxyProvidePeople(peopleModule)); PeopleActivity_MembersInjector.injectMPresenter( instance, PeopleModule_ProvidePeoplePresenterFactory.proxyProvidePeoplePresenter(peopleModule)); return instance; } public static final class Builder { private PeopleModule peopleModule; private Builder() {} public PeopleComponent build() { if (peopleModule == null) { this.peopleModule = new PeopleModule(); } return new DaggerPeopleComponent(this); } public Builder peopleModule(PeopleModule peopleModule) { this.peopleModule = Preconditions.checkNotNull(peopleModule); return this; } }}
注解@Module和注解@Binds
对于抽象类和接口的注入,我们还可以使用注解@Binds
实现,使用注解@Binds
有如下要求:
- 必须用在Module里的抽象方法
- 必须为抽象方法
- 必须有一个参数,参数类型可以分配给方法的返回类型
对上面的例子进行下修改:
@Modulepublic abstract class PeopleModule { @Binds abstract People bindStudent(Student student); @Binds abstract PeopleContract.Presenter bindPeoplePresenter(PeoplePresenter presenter);}
这时我们需要给提供的注入类型添加空的构造方法,然后添加@Inject
注解:
public class Student extends People { @Inject public Student() { } @Override String doWhat() { return "study"; }}public class PeoplePresenter implements PeopleContract.Presenter { @Inject public PeoplePresenter() { } ...}
生成的代码;
public final class DaggerPeopleComponent implements PeopleComponent { private DaggerPeopleComponent(Builder builder) {} ... private PeopleActivity injectPeopleActivity(PeopleActivity instance) { PeopleActivity_MembersInjector.injectPeople(instance, new Student()); PeopleActivity_MembersInjector.injectMPresenter(instance, new PeoplePresenter()); return instance; } ...}
这可以实现和使用@Provides
注解相同的功能,这里推荐使用@Binds
注解实现注入功能。
总结
- 使用注解
@Inject
和注解@Component
可以完成简单的依赖注入 - 注解
@Component
只能用在接口或抽象类上,会自动生成以Dagger为前缀的实现类 - 注解
@Inject
用在构造方法上表示可以使用此构造方法提供需要的实例,如果构造方法包含参数,也会对其参数完成注入 - 注解
@Inject
可以用在非private的成员变量和成员方法上完成依赖注入,推荐使用成员变量注入的方式 - 对于无法在构造方法上使用
@Inject
注解提供实例的情况,可以使用注解@Module
和注解@Provides
提供依赖实例,注意需要在Component类指定Module类 - 对于抽象类和接口的注入,也可以使用注解
@Module
和注解@Binds
实现,注解@Binds
用在抽象方法上,返回类型为需要注入的类型,包含一个可以分配给返回类型的参数,推荐使用注解@Binds
完成依赖注入,注意需要在参数的构造方法上添加@Inject
注解以提供对应实例
参考
- https://google.github.io/dagger/
- https://www.jianshu.com/p/24af4c102f62
- http://www.cnblogs.com/tiantianbyconan/p/5092083.html
更多相关文章
- Android更新UI的方法
- Eclipse中编译Android工程时出现的问题解决方法。
- Android编程之文件的读写实例详解
- Android studio获取证书指纹 (SHA1)的方法
- Android 解析XML文件方法
- Android与JS之间跨平台异步调用实例详解
- Android 的实现TextView中文字链接的4种方法
- Android浮动窗口实现原理及代码实例