[译] 全新 Android 注入器:Dagger 2(一)

@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。它们都拥有自己的 ModuleComponent,但是它们与我在上面 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:这个 ModuleMainActivity 提供了相关实例对象(例如 MainActivityPresenter)。你注意到 provideMainView() 方法将 MainActivity 作为参数了吗?没错,我们利用 MainActivityComponent 创建了我们所需的对象。因此 Dagger 将我们的 Activity 加入到 图谱中并因此能使用它。

@Module
public class MainActivityModule {

@Provides
MainView provideMainView(MainActivity mainActivity){
return mainActivity;
}

@Provides
MainPresenter provideMainPresenter(MainView mainView, ApiService apiService){
return new MainPresenterImpl(mainView, apiService);
}
}

同样的,我们可以像创建 MainActivityComponentMainActivityModule 一样创建 DetailActivityComponentDetailActivityModule,因此具体步骤就略过了。

Fragment Components

如果在 DetailActivity 中有两个 Fragment,那我们应该怎么办呢?实际上这一点都不难想到。先想想 Activity 和 Application 之间的关系,Application 通过映射的 Module(在我的示例中就是ActivityBuilder)知道所有的 Activity,并且将所有的 Activity 作为子 Component 加入到 AppModule 中。

Activity 和 Fragment 也是如此,首先创建一个 FragmentBuilder Module 加入到 DetailActivityComponent 中。

现在我们就可以像之前创建 MainActivityComponentMainActivityModule 一样来创建 DetailFragmentComponentDetailFragmentModule了。

DispatchingAndroidInjector

最后我们需要做的便是注入到注入器中。注入器的作用是什么?我想用一段简单的代码解释下。

public class AndroidSampleApp extends Application implements HasActivityInjector {

@Inject
DispatchingAndroidInjector activityDispatchingAndroidInjector;

@Override
public void onCreate() {
super.onCreate();
//simplified
}

@Override
public DispatchingAndroidInjector activityInjector() {
return activityDispatchingAndroidInjector;
}
}

Application 拥有很多 Activity,这就是我们实现 HasActivityInjector 接口的原因。那 Activity 有多个 Fragment 呢?意思是我们需要在 Activity 中实现 HasFragmentInjector 接口吗?没错,我就是这个意思!

public class DetailActivity extends AppCompatActivity implements HasSupportFragmentInjector {

@Inject
DispatchingAndroidInjector fragmentDispatchingAndroidInjector;

//simplified

@Override
public AndroidInjector supportFragmentInjector() {
return fragmentDispatchingAndroidInjector;
}
}

如果你没有子 Fragment 你不需要注入任何东西到 Fragment,那你也不需要实现 HasSupportFragmentInjector 接口了。但是在我们的示例中需要在 DetailActivity 创建一个 DetailFragment

AndroidInjection.inject(this)

做这些都是为了什么?这是因为 Activity 和 Fragment 都不应该是如何被注入的,那我们应该如何注入呢?

在 Activity 中:

@Override
protected void onCreate(Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
}

在 Fragment 中:

@Override
public void onAttach(Context context) {
**AndroidSupportInjection.inject(this);
** super.onAttach(context);
}

没错,恭喜你,所有工作都完成了!

我知道这有点复杂,学习曲线很陡峭,但是我们还是达到目的了。现在,我们的类是不知道如何被注入的。我们可以将所需实例对象通过 @Inject annotation 注解注入到我们的 UI 元素。
你可以在我的 GitHub 主页找到这个工程,我建议你对照着 Dagger 2 的官方文档看。
iammert/dagger-android-injection _dagger-android-injection - Sample project explains Dependency Injection in Android using dagger-android framework._github.com
Dagger ‡ A fast dependency injector for Android and Java. A fast dependency injector for Android and Java.google.github.io
在第二部分,我想利用 Dagger 提供的新注解来简化 android-dagger 注入,但是在简化之前我想先给大家看看它原来的样子。
第二部分在这里了。
感谢阅读,祝你编码愉快!


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 AndroidiOS前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

推荐学习资料


  • 脑图
    360°全方位性能调优

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

难做到真正的技术提升。**

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 22
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值