- 原文地址:New Android Injector with Dagger 2—part 1
- 原文做者:Mert Şimşek
- 譯文出自:掘金翻譯計劃
- 本文永久連接:github.com/xitu/gold-m…
- 譯者:MummyDing
- 校對者:LeviDing
Dagger 2.10 新增了 Android Support 和 Android Compiler 兩大模塊。對咱們來講,本次改動很是之大,全部 Android 開發者都應儘早嘗試使用這個新的 Android 依賴注入框架。html
在我開始介紹新的 AndroidInjector 類以及 Dagger 2.11 庫以前,若是你對 Dagger 2 還不熟悉甚至以前根本沒用過,那我強烈建議你先去看看 Dagger 入門指南,弄清楚什麼是依賴注入。爲何這麼說呢?由於 Android Dagger 涉及到大量註解,學起來會比較吃力。在我看來,學 Android Dagger 以前你最好先去學學 Dagger 2 和依賴注入。這裏有一篇關於依賴注入的入門文章 Blog 1 以及一篇關於 Dagger 2 的文章 Blog 2。前端
Dagger 2.10 以前,Dagger 2 是這樣用的:java
((MyApplication) getApplication())
.getAppComponent()
.myActivity(new MyActivityModule(userId))
.build()
.inject(this);
複製代碼
這會有什麼問題呢?咱們想用依賴注入,可是依賴注入的核心原則是什麼?android
一個類不該該關心它是如何被注入的ios
所以咱們必須把這些 Builder 方法和 Module 實例建立部分去掉。git
我建立的示例工程中沒作什麼,我想讓它儘量地簡單。它裏面僅包含 MainActivity
和 DetailActivity
兩個 Activity,它們都注入到了相應的 Presenter 實現類而且請求了網絡接口(並非真的發起了 HTTP 請求,我只是寫了一個假方法)。github
在 build.gradle 中加入如下依賴:數據庫
compile 'com.google.dagger: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。api
先彆着急,我後面會解釋 @Subcomponent,@Component 以及 DispatchActivity
都是什麼的。如今只是想讓你對 @Component 和 @Subcomponent 有一個大概瞭解。
**@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()
方法。
DaggerAppComponent
._builder_()
**.application(this)**
.build()
.inject(this);
複製代碼
從上面的代碼能夠看出,咱們將 Application 實例綁定到了 Dagger 圖譜中。
我想你們已經對 @Component.Builder 和 @Component 有了必定的認識,下面我想說說工程的結構。
使用 Dagger 的時候咱們能夠將 App 分爲三層:
@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。
@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);
}
複製代碼
@Module(subcomponents = {
MainActivityComponent.class,
DetailActivityComponent.class})
public class AppModule {
@Provides
@Singleton
Context provideContext(Application application) {
return application;
}
}
複製代碼
咱們有兩個 Activity:MainActivity
and DetailActivity
。它們都擁有本身的 Module 和 Component,可是它們與我在上面 AppModule
中定義的同樣,也是子 Component。
@Subcomponent(modules = MainActivityModule.class)
public interface MainActivityComponent extends AndroidInjector<MainActivity>{
@Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<MainActivity>{}
}
複製代碼
MainActivity
提供了相關實例對象(例如 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);
}
}
複製代碼
一樣的,咱們能夠像建立 MainActivityComponent
和 MainActivityModule
同樣建立 DetailActivityComponent
和 DetailActivityModule
,所以具體步驟就略過了。
若是在 DetailActivity
中有兩個 Fragment,那咱們應該怎麼辦呢?實際上這一點都不難想到。先想一想 Activity 和 Application 之間的關係,Application 經過映射的 Module(在個人示例中就是ActivityBuilder)知道全部的 Activity,而且將全部的 Activity 做爲子 Component 加入到 AppModule 中。
Activity 和 Fragment 也是如此,首先建立一個 FragmentBuilder Module 加入到 DetailActivityComponent 中。
如今咱們就能夠像以前建立 MainActivityComponent
和 MainActivityModule
同樣來建立 DetailFragmentComponent
和 DetailFragmentModule
了。
最後咱們須要作的即是注入到注入器中。注入器的做用是什麼?我想用一段簡單的代碼解釋下。
public class AndroidSampleApp extends Application implements HasActivityInjector {
@Inject
DispatchingAndroidInjector<Activity> activityDispatchingAndroidInjector;
@Override
public void onCreate() {
super.onCreate();
//simplified
}
@Override
public DispatchingAndroidInjector<Activity> activityInjector() {
return activityDispatchingAndroidInjector;
}
}
複製代碼
Application 擁有不少 Activity,這就是咱們實現 HasActivityInjector 接口的緣由。那 Activity 有多個 Fragment 呢?意思是咱們須要在 Activity 中實現 HasFragmentInjector 接口嗎?沒錯,我就是這個意思!
public class DetailActivity extends AppCompatActivity implements HasSupportFragmentInjector {
@Inject
DispatchingAndroidInjector<Fragment> fragmentDispatchingAndroidInjector;
//simplified
@Override
public AndroidInjector<Fragment> supportFragmentInjector() {
return fragmentDispatchingAndroidInjector;
}
}
複製代碼
若是你沒有子 Fragment 你不須要注入任何東西到 Fragment,那你也不須要實現 HasSupportFragmentInjector 接口了。可是在咱們的示例中須要在 DetailActivity
建立一個 DetailFragment
。
作這些都是爲了什麼?這是由於 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 的官方文檔看。
在第二部分,我想利用 Dagger 提供的新註解來簡化 android-dagger 注入,可是在簡化以前我想先給你們看看它原來的樣子。
第二部分在這裏了。
感謝閱讀,祝你編碼愉快!
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。