Dagger 2.10 新增了 Android Support 和 Android Compiler 两大模块。对我们来说,本次改动非常之大,所有 Android 开发者都应尽早尝试使用这个新的 Android 依赖注入框架。
在我开始介绍新的 AndroidInjector 类以及 Dagger 2.11 库之前,如果你对 Dagger 2 还不熟悉甚至之前根本没用过,那我强烈建议你先去看看 Dagger 入门指南,弄清楚什么是依赖注入。为什么这么说呢?因为 Android Dagger 涉及到大量注解,学起来会比较吃力。在我看来,学 Android Dagger 之前你最好先去学学 Dagger 2 和依赖注入。这里有一篇关于依赖注入的入门文章 Blog 1 以及一篇关于 Dagger 2 的文章 Blog 2。
老用法
Dagger 2.10 之前,Dagger 2 是这样用的:
((MyApplication) getApplication())
.getAppComponent()
.myActivity(new MyActivityModule(userId))
.build()
.inject(this);
这会有什么问题呢?我们想用依赖注入,但是依赖注入的核心原则是什么?
一个类不应该关心它是如何被注入的
因此我们必须把这些 Builder 方法和 Module 实例创建部分去掉。
示例工程
我创建的示例工程中没做什么,我想让它尽可能地简单。它里面仅包含 MainActivity
和 DetailActivity
两个 Activity,它们都注入到了相应的 Presenter 实现类并且请求了网络接口(并不是真的发起了 HTTP 请求,我只是写了一个假方法)。
准备工作
在 build.gradle 中加入以下依赖:
compile ‘com.google.dagger🗡2.11-rc2’
annotationProcessor ‘com.google.dagger:dagger-compiler:2.11-rc2’
compile ‘com.google.dagger:dagger-android-support:2.11-rc2’
工程包结构
Application
类利用 AppComponent
构建了一张图谱。AppComponent
类的头部都被加上 @Component 注解,当 AppComponent
利用它的 Module 进行构建的时候,我们将得到一张拥有所有所需实例对象的图谱。举个例子,当 App Module 提供了ApiService
,我们在构建拥有 App Module 的 Component 时将会得到 ApiService
实例对象。
如果我们想将 Activity 加入到 Dagger 图谱中从而能够直接从父 Compponent 直接获取所需实例,我们只需简单地将 Activity 加上 @Subcomponent 注解即可。在我们的示例中,DetailActivityComponent
和 MainActivityComponent
类都被加上了 @Subcomponent 注解。最后我们还有一个必需步骤,我们需要告诉父 Component 相关的子 Component 信息,因此所有的根 Compponent 都能知道它所有的子 Component。
先别着急,我后面会解释 @Subcomponent,@Component 以及 DispatchActivity
都是什么的。现在只是想让你对 @Component 和 @Subcomponent 有一个大概了解。
@Component and @Component.Builder
@Component(modules = {
AndroidInjectionModule.class,
AppModule.class,
ActivityBuilder.class})
public interface AppComponent {
@Component.Builder
interface Builder {
@BindsInstance Builder application(Application application);
AppComponent build();
}
void inject(AndroidSampleApp app);
}
**@Component:**Component 是一个图谱。当我们构建一个 Component时,Component 将利用 Module 提供被注入的实例对象。
**@Component.Builder:**我们可能需要绑定一些实例对象到 Component 中,这种情况我们可以通过创建一个带 @Component.Builder 注解的接口,然后就可以向 builder 中任意添加我们想要的方法。在我的示例中,我想将 Application
加入到 AppComponent
中。
注意:如果你想为你的 Component 创建一个 Builder,那你的 Builder 接口中需要有一个返回类型为你所创建的 Component 的
builder()
方法。
注入 AppComponent
DaggerAppComponent
.builder()
.application(this)
.build()
.inject(this);
从上面的代码可以看出,我们将 Application 实例绑定到了 Dagger 图谱中。
我想大家已经对 @Component.Builder 和 @Component 有了一定的认识,下面我想说说工程的结构。
Component/Module 结构
使用 Dagger 的时候我们可以将 App 分为三层:
- Application Component
- Activity Components
- Fragment Components
Application Component
@Component(modules = {
AndroidInjectionModule.class,
AppModule.class,
ActivityBuilder.class})
public interface AppComponent {
@Component.Builder
interface Builder {
@BindsInstance Builder application(Application application);
AppComponent build();
}
void inject(AndroidSampleApp app);
}
每个 Android 应用都有一个 Application
类,这就是为什么我也有一个 Application Component 的原因。这个 Component 表示是为应用层面提供实例的 (例如 OkHttp, Database, SharedPrefs)。这个 Component 是 Dagger 图谱的根,在我们的应用中 Application Component 提供了三个 Module。
- AndroidInjectionModule:这个类不是我们写的,它是 Dagger 2.10 中的一个内部类,通过给定的 Module 为我们提供了 Activity 和 Fragment。
- ActivityBuilder:我们自己创建的 Module,这个 Module 是给 Dagger 用的,我们将所有的 Activity 映射都放在了这里。Dagger 在编译期间能获取到所有的 Activity,我们的 App 中有 MainActivity 和 DetailActivity 两个 Activity,因此我将这两个 Activity 都放在这里。
@Module
public abstract class ActivityBuilder {
@Binds
@IntoMap
@ActivityKey(MainActivity.class)
abstract AndroidInjector.Factory<? extends Activity> bindMainActivity(MainActivityComponent.Builder builder);
@Binds
@IntoMap
@ActivityKey(DetailActivity.class)
abstract AndroidInjector.Factory<? extends Activity> bindDetailActivity(DetailActivityComponent.Builder builder);
}
- AppModule:我们在这里提供了 retrofit、okhttp、持久化数据库、SharedPrefs。其中有一个很重要的细节,我们必须将子 Component 加入到 AppModule 中,这样 Dagger 图谱才能识别。
@Module(subcomponents = {
MainActivityComponent.class,
DetailActivityComponent.class})
public class AppModule {
@Provides
@Singleton
Context provideContext(Application application) {
return application;
}
}
Activity Components
我们有两个 Activity:MainActivity
and DetailActivity
。它们都拥有自己的 Module 和 Component,但是它们与我在上面 AppModule
中定义的一样,也是子 Component。
- MainActivityComponent:这个 Component 是连接 MainActivityModule 的桥梁,但是有一个很关键的不同点就是不需要在 Component 中添加 inject() 和 build() 方法。MainActivityComponent 会从父类中集成这些方法。AndroidInjector 类是 dagger-android 框架中新增的。
@Subcomponent(modules = MainActivityModule.class)
public interface MainActivityComponent extends AndroidInjector{
@Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder{}
}
- MainActivityModule:这个 Module 为
MainActivity
提供了相关实例对象(例如MainActivityPresenter
)。你注意到 provideMainView() 方法将 MainActivity 作为参数了吗?没错,我们利用 MainActivityComponent 创建了我们所需的对象。因此 Dagger 将我们的 Activity 加入到 图谱中并因此能使用它。
@Module
public class MainActivityModule {
最后我还整理了很多Android中高级的PDF技术文档。以及一些大厂面试真题解析文档。
Android高级架构师之路很漫长,一起共勉吧!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
真正的技术提升。**
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!