@Binds - Dagger2

インターフェースを実装したクラスがあり、それをインターフェース経由でバインドしたいとき、通常以下のようにしてました。


@Module
object BookPresenterModule {
  @Provides @JvmStatic
  fun provideBookPresenter(bookPresenter: BookPresenterImpl): BookPresenter = bookPresenter
}

これは @Inject 付きコンストラクタと一緒に使われるモジュールの一部です。これは、以下のように記述するべきです。


@Module
abstract class BookPresenterModule {
  @Binds abstract fun bindBookPresenter(bookPresenter: BookPresenterImpl): BookPresenter
}

これまでどおり「インターフェースにその実装をバインドしたいとき」に使うことができます。

コード生成がされず、どこからもコールされないのに、きちんと連携情報として利用されるのが良いところです。

Dagger 2.4 で登場したにもかかわらず、なぜか公式ユーザーガイドでは説明されていません。

👉 Release Dagger 2.4 · google/dagger 

以下、公演動画などから学ぶことができます。




ApplicationComponent 実装の変遷 - Dagger2

2022-03-16 追記: 新しいDagger記事は以下リンクから

👉 MVVM で Hilt のパターン化 💉  

--------

へん‐せん【変遷】
[名](スル)時の流れとともに移り変わること。「歌もまた時代につれて変遷する」

Dagger て分かりづらいです。

タイトルがすでに謎ですが、以下のような実装のことを指しています。

アプリケーションコンテキストをオブジェクトグラフに追加する

ApplicationComponent とアプリケーションコンテキストの設定

アプリケーションコンテキスト を依存先として公開する

これまで数年に渡って変化し続けてるそんな必須の実装項目です。

ネット上をただ検索するだけでは、古い記事に最新の実装記述が埋没しています。

Dagger 2.9 以前( - 2017/02/04)


@Component(modules = [ApplicationModule::class, ...])
interface ApplicationComponent {
  ...
}


@Module
class ApplicationModule(private val applicationContext: Context) {
  @Provides fun provideApplicationContext() = applicationContext
}

これは Kotlin 記述で簡略化できます。


@Module
class ApplicationModule(@get:Provides val applicationContext: Context)


DaggerApplicationComponent
  .builder()
  .applicationModule(ApplicationModule(applicationContext))
  .build()

2.9 (2017/02/04 - ) @BindsInstance

👉 Release Dagger 2.9 · google/dagger 

We create a module that receives the application context as a constructor argument, and we create a provide method that exposes it. This works great, but then we can't have static @Provides methods anymore. And besides that, this strategy is actually going against the docs that are pretty explicit when it comes to this:

@BindsInstance methods should be preferred to writing a @Module with constructor arguments and immediately providing those values.

👉 User's Guide 


@Component(modules = ...)
interface ApplicationComponent {
  @Component.Builder
  interface Builder {
    @BindsInstance 
    fun applicationContext(applicationContext: Context): Builder
    fun build(): ApplicationComponent
  }
  ...
}


DaggerApplicationComponent
  .builder()
  .applicationContext(applicationContext)
  .build()

2.22 (2019/04/03 - ) @Component.Factory

👉 Release Dagger 2.22 · google/dagger 


@Component(modules = ...)
interface ApplicationComponent {
  @Component.Factory
  interface Factory {
    fun create(@BindsInstance applicationContext: Context): ApplicationComponent
  }
  ...
}


DaggerApplicationComponent
  .factory()
  .create(applicationContext)

まとめ

最近のコード記述を理解するには、少しだけ

「成り立ちを遡ってみる」

と理解しやすいことが多いように思います。

👉 Releases · google/dagger 
👉 Dagger 2 on Android: the shiny new @Component.Factory 

2022-03-16 追記: 新しいDagger記事は以下リンクから

👉 MVVM で Hilt のパターン化 💉