（メモ）Glide v4のAppGlideModuleにOkHttpClientをInjectする


# 前提

既にDagger2によるDIをかっちり組んでOkHttpClientをInjectしているプロジェクトで、新たにGlide v4を導入する場合。

# 参考にしたコード

[How to inject OkHttpClient instance · Issue #2002 · bumptech/glide](https://github.com/bumptech/glide/issues/2002)

# サンプルコード

[リポジトリ](https://github.com/teracy/CustomAppGlideModuleSample)

issueではApplicationをSingletonにしてインスタンスを参照するような解決方法でしたが、どうせregisterComponentsでapplicationContextを突っ込むならそこでInjectすればよかろうと考えました。

AppGlideModule用にSubcomonentを定義し、DaggerApplication派生のApplicationクラスにinjectメソッドを追加しました。

## 新たに追加する分

AppGlideModuleはregisterComponentsに前述の処理を加えた以外はセオリー通りです。

### AppGlideModule

```kotlin:CustomAppGlideModule.kt
@GlideModule(glideName = "CustomGlideApp")
class CustomAppGlideModule : AppGlideModule() {
    @Inject
    lateinit var okHttpClient: OkHttpClient

    override fun isManifestParsingEnabled() = false

    override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
        super.registerComponents(context, glide, registry)
        (context.applicationContext as App).inject(this)
        glide.registry.replace(GlideUrl::class.java, InputStream::class.java, OkHttpUrlLoader.Factory(okHttpClient))
    }
}
```

### Subcomponent

SubcomponentにはBuilderを定義しています。

```kotlin:GlideComponent.kt
@Subcomponent
interface GlideComponent {
    fun inject(appGlideModule: CustomAppGlideModule)

    @Subcomponent.Builder
    interface Builder {
        fun build(): GlideComponent
    }
}
```

## 既存のものに変更する分

### AppModule
AppModuleはsubcomponentsアノテーションに先述のSubcomponentを追加するだけです。

```kotlin:AppModule.kt
@Module(subcomponents = [GlideComponent::class])
internal object AppModule {
    // 以下は既存のものそのままなので略
}
```

### AppComponent

AppComponentにはSubcomponentのBuilderを生成するメソッドを追加します。

```kotlin:AppComponent.kt
@Singleton
@Component(modules = [
    AndroidSupportInjectionModule::class,
    AppModule::class,
    MainActivityBuilder::class,
    ViewModelModule::class
])
interface AppComponent : AndroidInjector<App> {
    @Component.Builder
    interface Builder {
        @BindsInstance
        fun application(application: Application): Builder

        fun build(): AppComponent
    }

    override fun inject(application: App)

    // 以下新しく追加
    fun glideComponentBuilder(): GlideComponent.Builder
}
```

### Application

ApplicationはInjectメソッドを追加します。

```kotlin:App.kt
class App : DaggerApplication() {
    override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
        return DaggerAppComponent.builder()
                .application(this)
                .build()
    }

    override fun onCreate() {
        super.onCreate()
        if (BuildConfig.DEBUG) {
            Timber.plant(Timber.DebugTree())
        }
    }

    // 以下新しく追加
    fun inject(appGlideModule: CustomAppGlideModule) {
        (applicationInjector() as AppComponent).glideComponentBuilder().build().inject(appGlideModule)
    }
}
```

後はViewで利用するだけです。

```kotlin:MainActivity.kt
class MainActivity : DaggerAppCompatActivity() {
    @Inject
    lateinit var viewModelFactory: ViewModelProvider.Factory

    private lateinit var viewModel: MainViewModel
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        CustomGlideApp.with(this)
                .load("https://qiita-image-store.s3.amazonaws.com/0/21354/profile-images/1473683312")
                .into(binding.image)

        viewModel = ViewModelProviders.of(this, viewModelFactory).get(MainViewModel::class.java)
    }
}
```

サンプルではQiitaの私のアイコンを読み込ませました。不気味です。

![サンプル](https://qiita-image-store.s3.amazonaws.com/0/21354/b30c42d7-2ad3-054c-c56d-bbe4e05171f5.png)