blog.bouzuya.net

2017-06-19 Dagger 2 の第一印象

昨日 (2017-06-18) のことだけど、ようやく Dagger 2bouzuya/bbna に適用した。第一印象を書いておく。

導入は簡単だった。

依存関係は app/build.gradledependencies に次の二行を入れて Android Studio の Sync Now で良い。

compile 'com.google.dagger:dagger:2.11'
annotationProcessor 'com.google.dagger:dagger-compiler:2.11'

最初につくる要素をいくつか挙げる。

  • @Module アノテーションをつけた XXXModule クラス
    • @Provides アノテーションをつけた provideYYY メソッドを持つ
  • @Component アノテーションをつけた XXXComponent インタフェース
  • @Inject アノテーションをつけたコンストラクタやフィールドを持つ XXX

ここまでつくると DaggerXXXComponent クラスが各アノテーションから生成される。DI コンテナってリフレクションで処理しているイメージを持っていたのだけど、 Dagger 2 はアノテーションプロセッサでクラスを生成するらしい。この DaggerXXXComponent の中身を見て、挙動が分かる雰囲気に安心した。

DaggerXXXComponentstatic Builder builder() を持っているので、 XXXComponent component = DaggerXXXComponent.builder().build(); な形で生成する。

ここまでを雰囲気で書くと↓な感じ。

interface YYY { void foo(); }

class YYYImpl { void foo() { /* ... */ } }

@Module
class XXXModule {
  @Provides
  YYY providesYYY() { return new YYYImpl(); }
}

@Component(modules = {XXXModule.class})
interface XXXComponent {
  void inject(XXX xxx);
}

class XXX extends Application {
  @Inject YYY yyy;
  @Override void onCreate() {
    XXXComponent component = DaggerXXXComponent.builder().build();
    component.inject(this);
  }
}

これだけでは inject() とは言うものの Dependency Injection より Service Locator のほうが適当っぽい。 ButterKnifeButterKnife.bind(this) が雰囲気は近い。あと Android の制約として Activity / Fragment の生成がシステムの制御下なので、 Activity への生成を DI ライブラリではできない。 Activity / Fragment へは何かしらの形で明示的な inject が要る。簡素化する仕組みは公式でも提供されているらしい

DaggerXXXComponent だけど、中身は Provider<T>Injector<T> でつぎはぎしている感じ。これらはインタフェースだけど、 @Provide@Inject に対応する形でクラスが自動生成される。 Provider の実装は生成タイミングの調整や連鎖的な依存関係を解決するためのファクトリっぽい。 Injector は各パッケージに配置する (フィールドインジェクションだと同一パッケージでないとね) ためのクラスっぽい。

まだ @Scope / @Subcomponent / @Qualifier などには触れていない。どう @Component を割るべきかなども考えられていない。また調べる。

公式がいまひとつピンとこないので、↓をはじめとした外部サイトをよく見ている。

https://github.com/codepath/android_guides/wiki/Dependency-Injection-with-Dagger-2

そんな感じ。たぶん、また書く。