Dagger2 + Retrofit2 + Moshi + Kotlin を使って通信するまで

Kotlin を学ぶ際に、まずは通信周りを勉強したので、そこで得た知識を記事にしました。

## Dagger2 + Retrofit2 + Moshi
Dagger2 + Retrofit2 + Moshi を導入する。

```gradle
buildscript {
    ext.kotlin_version = '1.3.11'
    ext.dagger_version = '2.19'
    ext.retrofit_version = '2.5.0'
    ext.moshi_version = '1.8.0'
...
```

```gradle
apply plugin: 'kotlin-kapt'
...
dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
...
    implementation "com.google.dagger:dagger:$dagger_version"
    implementation "com.google.dagger:dagger-android:$dagger_version"
    implementation "com.google.dagger:dagger-android-support:$dagger_version"
    kapt "com.google.dagger:dagger-compiler:$dagger_version"
    kapt "com.google.dagger:dagger-android-processor:$dagger_version"
    implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
    implementation "com.squareup.retrofit2:converter-moshi:$retrofit_version"
    implementation "com.squareup.moshi:moshi:$moshi_version"
    implementation "com.squareup.moshi:moshi-kotlin:$moshi_version"
```

このままだと、ビルド時にエラーが発生するので、「jetifier-processor」を追加する。

```gradle
    dependencies {
        classpath 'com.android.tools.build:gradle:3.2.1'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
...
        classpath 'com.android.tools.build.jetifier:jetifier-processor:1.0.0-beta02'
```

## Dagger2 を実装

Application - Component - 各 Module
の構成作る必要があるので、まず、Application と Component を作成する。

* Component

```kotlin
import dagger.BindsInstance
import dagger.Component
import dagger.android.AndroidInjector
import dagger.android.support.AndroidSupportInjectionModule
import javax.inject.Singleton

@Singleton
@Component(modules = [AndroidSupportInjectionModule::class])
interface AppComponent : AndroidInjector<App> {
    override fun inject(application: App)

    @Component.Builder
    interface Builder {
        @BindsInstance
        fun application(application: App): Builder

        fun build(): AppComponent
    }
}
```

* Application

```kotlin
import dagger.android.AndroidInjector
import dagger.android.support.DaggerApplication

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

* AndroidManifest

```xml
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:name=".App"
```

## Activity を実装

Activity の Module を作成する。

```kotlin
@Module
abstract class ActivityModule {
    @ContributesAndroidInjector
    abstract fun contributeMainActivity(): MainActivity
}
```

Component にモジュールを追加する。

```kotlin
@Component(modules = [AndroidSupportInjectionModule::class, ActivityModule::class])
interface AppComponent : AndroidInjector<App> {
...
```

AppCompatActivity を DaggerAppCompatActivity に変更する。

```kotlin
class MainActivity : DaggerAppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
...
```

## Retrofit2 + Moshi を実装

例として、GitHub のユーザ情報を取得する。

```kotlin
data class User(
    val name: String?,
    val company: String?,
    val email: String?,
    val bio: String?,
    val created_at: String?,
    val updated_at: String?
)
```

Retrofit2 の interface を作成する。

```kotlin
interface GitHubService {
    @GET("users/{username}")
    fun getUser(@Path("username") user: String): Call<User>
}
```

Retrofit2 の Module を作成する。

```kotlin
@Module
class RetrofitModule {
    @Provides
    @Singleton
    fun provideMoshi(): Moshi {
        return Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
    }

    @Provides
    @Singleton
    fun provideRetrofit(moshi: Moshi): Retrofit {
        return Retrofit.Builder()
            .baseUrl("https://api.github.com")
            .addConverterFactory(MoshiConverterFactory.create(moshi))
            .build()
    }

    @Provides
    @Singleton
    fun provideRetrofitService(retrofit: Retrofit): GitHubService = retrofit.create(GitHubService::class.java)
}
```

Component にモジュールを追加する。

```kotlin
@Component(modules = [AndroidSupportInjectionModule::class, ActivityModule::class, RetrofitModule::class])
interface AppComponent : AndroidInjector<App> {
...
```

依存性の注入をする。

```kotlin
class MainActivity : DaggerAppCompatActivity() {
    @Inject
    lateinit var github: GitHubService
```

GitHub のユーザ情報を取得する。

```kotlin
    override fun onResume() {
        super.onResume()

        val userCall: Call<User> = github.getUser("xxxxx")
        userCall.enqueue(object : Callback<User> {
            override fun onFailure(call: Call<User>, t: Throwable) {

            }

            override fun onResponse(call: Call<User>, response: Response<User>) {
                if (response.isSuccessful) {
                    val user: User? = response.body()
                }
            }
        })
    }
```

---
ここまでで、Dagger2 + Retrofit2 + Moshi + Kotlin を使って通信するまでを記載しました。
本来は、シングルトンや依存関係など色々考慮して実装する必要がありますが、Dagger2 を使用することで、Module を追加し、Inject するだけで、シングルトンや依存関係などを考慮する必要がなくなります。