[Android] Dagger2 導入してみた

Android

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Dagger2の導入

appのbuild.gradleを修正します。

apply plugin: 'android-apt'

dependencies {
  ...
  compile 'com.google.dagger:dagger:2.2'
  apt 'com.google.dagger:dagger-compiler:2.2'
  ...
}

Dagger2 基本構成

実装クラス

DIして利用するクラスです

public interface Sample {
    void greeting();
}

public class SampleImpl implements Sample {
    @Override
    void greeting() {
        Log.d("tag", "hello");
    }
}

Module

DIするクラスを指定する

@Module
public class SampleModule {
    @Provides
    SampleImpl provideSampleImpl() {
        return new SampleImpl();
    }
}

Component

DIさせる対象を設定する

@Component(modules = SampleModule.class)
public interface ActivityComponent {
    // MainActivityのメンバにinjectする
    // inject対象を引数にすることで、自動生成されるクラスのメソッド内でメンバへの注入処理が実装される
    // injectというメソッド名である必要はないが、用途を明確にするために推奨している
    void inject(MainActivity activity);
}

ビルドすると、DaggerActivityComponentが生成されている

public class MainActivity extends Activity {

    @Inject
    Sample mSample;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        DaggerActivityComponent.create().inject(this);
        // mSampleにSampleImplが注入されている
        mSample.greeting();
    }
}

少し応用

Dagger2には上記以外の要素として

  • Subcomponent
  • dependencies
  • Scope(Singleton)

といったものが存在する。(Lazyとかはまた別の機会で・・・)

SubComponent

  • Componentの親子関係を指定できる
  • 親Componentに子Componentを戻り値としたメソッドを用意する
    • つまり、親から子を指定する。
    • 子のDagger○○Componentは生成されないので、親のメソッドを利用して取得する
  • Scopeを分ける時などに利用

dependencies

  • Componentの依存関係を指定できる(親子と同じ)
  • 子Componentに依存先を記載する
    • 子から親を指定する
  • 子がDIに必要としているクラスは親に記載する
  • Scopeを分ける時などに利用

Scope

対象Component内にて、一意のインスタンスを供給する
(e.g., AppComponent内でOkHttpClientのインスタンスを使い回す)
@SingletonはDagger2が用意してくれているScopeにすぎない

あとがき

Dagger2はDIを導入する道具にすぎないので、
アプリを作る際には、どのような構成にするか・どこでDIを利用するか、などを決めていくことが重要だと感じました。
Dagger2のややこしさに惑わされ手段と目的が入れ替わることのないように注意したいです。

参考

Dagger ‡ A fast dependency injector for Android and Java.