[譯] 全新 Android 注入器 : Dagger 2(三)

Landroid發表於2017-12-25

全新 Android 注入器 : Dagger 2(三)

如果你還沒有閱讀(一)和(二),我建議你先閱讀它們。

概要

你可以使用 DaggerActivityDaggerFragmentDaggerApplication 來減少 Activity/Fragment/Application 類裡面的模板程式碼。

同樣的,在 daggercomponent 中,你也可以通過 AndroidInjector<T> 去減少模板程式碼。

DaggerAppCompatActivity and DaggerFragment

在使用 daggerfragment 或者 activity 中要記得呼叫 AndroidInjection.inject() 方法。 同樣的,如果你想要在 v4 包裡面的 fragment 中使用 Injection,你應該讓你的 activity 實現 HasSupportFragmentInject 介面並且重寫 fragmentInjector 方法。

最近,我把這些相關程式碼移到 BaseActivityBaseFragment。因為與其在每個 activity 中宣告這些,還不如把共同的程式碼放到基類裡面。

於是我在研究 dagger 專案的時候發現 DaggerAppCompatActivityDaggerFragment 這些類正好是我所需要的。如果說 Android 喜歡繼承,那麼我們也可以假裝喜歡繼承 ?

讓我們看看這些類做了些神馬。

@Beta
public abstract class DaggerAppCompatActivity extends AppCompatActivity
    implements HasFragmentInjector, HasSupportFragmentInjector {

  @Inject DispatchingAndroidInjector<Fragment> supportFragmentInjector;
  @Inject DispatchingAndroidInjector<android.app.Fragment> frameworkFragmentInjector;

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

  @Override
  public AndroidInjector<Fragment> supportFragmentInjector() {
    return supportFragmentInjector;
  }

  @Override
  public AndroidInjector<android.app.Fragment> fragmentInjector() {
    return frameworkFragmentInjector;
  }
}
複製程式碼

從上面的程式碼可以看出 DaggerAppCompatActivity 跟我們自己寫的 Activity 並沒有多大的區別,所以可以讓我們的 Activity 以繼承 DaggerAppCompatActivity 的方式來減少模板程式碼。

DetailActivity 類如下:

public class DetailActivity extends AppCompatActivity implements HasSupportFragmentInjector, DetailView {

    @Inject
    DispatchingAndroidInjector<Fragment> fragmentDispatchingAndroidInjector;

    @Inject
    DetailPresenter detailPresenter;

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

    @Override
    public void onDetailLoaded() {}

    @Override
    public AndroidInjector<Fragment> supportFragmentInjector() {
        return fragmentDispatchingAndroidInjector;
    }
}
複製程式碼

讓我們的 DetailActivity 繼承 DaggerAppCompatActivity 類,這樣我們就不用讓 DetailActivity 類實現 HasSupportFragmentInjector 介面以及重寫方法了。

public class DetailActivity extends DaggerAppCompatActivity implements DetailView {

    @Inject
    DetailPresenter detailPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_detail);
    }

    @Override
    public void onDetailLoaded() {}
}
複製程式碼

現在,是不是更簡潔了。

DaggerApplication, AndroidInjector, AndroidSupportInjectionModule

看看還有哪些辦法能夠減少模板程式碼。我發現 AndroidInjector 能夠幫助簡化 AppComponent。你可以通過閱讀 AndroidInjector 相關文件來獲取相關資訊。

下面是 AppComponent 類的程式碼。

@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);
}
複製程式碼

build()seedInstance() 方法已經在 AndroidInjector.Builder 抽象類中定義了,所以我們的 Builder 類可以通過繼承 AndroidInjection.Builder<Application> 來去掉上面程式碼中 application()build() 這兩個方法。

同樣的,AndroidInjector 介面中已經有 inject() 方法了。所以我們可以通過繼承 AndroidInjector<Application> 介面(介面是可以繼承介面的)來刪除 inject() 方法。

那麼我們簡化後的 AppComponent 介面的程式碼如下:

@Component(modules = {
        AndroidSupportInjectionModule.class,
        AppModule.class,
        ActivityBuilder.class})
interface AppComponent extends AndroidInjector<AndroidSampleApp> {
    @Component.Builder
    abstract class Builder extends AndroidInjector.Builder<AndroidSampleApp> {}
}
複製程式碼

你有沒有意識到我們的 modules 屬性也改變了?我從 @Component 註解的 modules 屬性中移除了 AndroidInjectionModule.class 並且新增了 AndroidSupportInjectionModule.class。這是因為我們使用的是支援庫(v4庫)的 Fragment。而 AndroidInjectionModule 是用來繫結 app 包的 Fragmentdagger。所以如果你想在 v4.fragment 中使用注入,那麼你應該在你的 AppComponent modules 中新增 AndroidSupportInjectionModule.class

我們改變了 AppComponent 的注入方式。那麼 Application 類需要做什麼改變。

DaggerActivityDaggerFragment 一樣,我們也讓 Application 類繼承 DaggerApplication 類。

之前的 Application 類的程式碼如下:

public class AndroidSampleApp extends Application implements HasActivityInjector {

    @Inject
    DispatchingAndroidInjector<Activity> activityDispatchingAndroidInjector;

    @Override
    public void onCreate() {
        super.onCreate();
        DaggerAppComponent
                .builder()
                .application(this)
                .build()
                .inject(this);
    }

    @Override
    public DispatchingAndroidInjector<Activity> activityInjector() {
        return activityDispatchingAndroidInjector;
    }
}
複製程式碼

修改後程式碼如下:

public class AndroidSampleApp extends DaggerApplication {

    @Override
    protected AndroidInjector<? extends AndroidSampleApp> applicationInjector() {
        return DaggerAppComponent.builder().create(this);
    }
}
複製程式碼

原始碼

你可以從我的 GitHub 上獲取修改後的原始碼。我沒有把這些程式碼 merge 到主分支上,是因為我想在各個分支中儲存 dagger 使用方式的歷史記錄。這樣讀者們就能夠知道我是如何一步步簡化 dagger 的使用方式。

PS.

我並不是說這是 dagger 的最優美的實踐方式。這只是我在自己專案中使用 dagger 的方式。如果喜歡的話,你也可以在自己的專案中這樣使用。如果你實在不想讓自己的 Application 類繼承第三方的 Application 類就別這樣使用(你可以把 DaggerApplication 的程式碼拷貝到你自己的App類裡面,把 DaggerActivity/DaggerFragment 裡面的程式碼拷貝到你自己的 BaseActivity/BaseFragment 中,如果你繼承的是 AppCompatActivity 就使用 DaggerAppCompatActivity。 ),你高興就好。最後,如果你們有更好的建議還請多多指教。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章