【Retorofit】コピペで使える NetworkModule【Dagger Hilt】

もうこれはテンプレ化しておきます。

Retrofit の話が中心となります。

👉 Retrofit 

 

Converter

Retrofit-Converters

JSON 形式のレスポンスをパースして変換するのは、Gson か Moshi が人気のように思います。


var retrofit = Retrofit.Builder()
  .baseUrl("https://api.example.com")
  .addConverterFactory(GsonConverterFactory.create())
  .build()


var retrofit = Retrofit.Builder()
  .baseUrl("https://api.example.com")
  .addConverterFactory(MoshiConverterFactory.create())
  .build()

👉 retrofit/retrofit-converters at master · square/retrofit 

今回は、Kotlin Serialization を利用した「Kotlin Serialization Converter」を使います。

ExperimentalSerializationApi なのですがね。


val contentType = "application/json".toMediaType()
val retrofit = Retrofit.Builder()
    .baseUrl("https://example.com/")
    .addConverterFactory(Json.asConverterFactory(contentType))
    .build()

👉 JakeWharton/retrofit2-kotlinx-serialization-converter: A Retrofit 2 Converter.Factory for Kotlin serialization. 

 

Call Adapter

Retrofit CallAdapters

通信の非同期処理はどれに任せるか。


var retrofit = Retrofit.Builder()
  .baseUrl("https://api.example.com")
  .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
  .build()

👉 retrofit/retrofit-adapters at master · square/retrofit 

Coroutine を使った Jake製の「Kotlin Coroutine Adapter」は 今では DEPRECATED。

👉 JakeWharton/retrofit2-kotlin-coroutines-adapter: A Retrofit 2 adapter for Kotlin coroutine's Deferred type. 

Retrofit は 2.6.0+ で、内部に suspend function をサポートしてるので、特に、.addCallAdapterFactory() を使わなくてもよい。


@GET("users/{id}")
suspend fun user(@Path("id") id: Long): User

👉 retrofit/CHANGELOG.md at master · square/retrofit 

 

HttpLoggingInterceptor

OkHttpClient に HTTP関連のログを吐かせます。


--> POST /greeting http/1.1
Host: example.com
Content-Type: plain/text
Content-Length: 3

Hi?
--> END POST

<-- 200 OK (22ms)
Content-Type: plain/text
Content-Length: 6

Hello!
<-- END HTTP

👉 HttpLoggingInterceptor.Level (OkHttp Logging Interceptor 3.14.0 API) 


val logging = HttpLoggingInterceptor()
logging.setLevel(Level.BASIC)
val client = OkHttpClient.Builder()
  .addInterceptor(logging)
  .build()

👉 okhttp/okhttp-logging-interceptor at master · square/okhttp 

 

まとめ

Dagger の Module にしておきます。

テンプレート化してください、と言わんばかりに

よく似たものをあちこちで見かけますよね。

見通しも良くなります。

コピペでどうぞ。

(おわり)



MVVM で Hilt のパターン化 💉

シンプルなものにして整理、定型化しておきたい。

「どこに」←「どれを」インジェクトしてるか、とそれの記述をパターン化。

 

💉 View ← ViewModel

MVVM でいうところの View であるこれらに、ViewModel をインジェクトする場合。

コンストラクタからインジェクトできないいわゆる「Androidクラス」。
以下のものがこれに当てはまる。

- Activity
- Fragment
- View
- Service
- BroadcastReceiver

それぞれのクラスに付ける2つのアノテーションと ktx による記述でプロパティにインジェクトする。


@AndroidEntryPoint
class MainFragment : Fragment() {
  private val viewModel: MainViewModel by viewModels()


@HiltViewModel
class MainViewModel @Inject constructor(
  repository: MainRepository
) : ViewModel() {

 


💉 ViewModel ← Repository

Module を使った ViewModel コンストラクタへのインジェクト。

インターフェースの型でリンクする。


@HiltViewModel
class MainViewModel @Inject constructor(
  repository: MainRepository
) : ViewModel() {

Hilt 備え付けの Component でライフサイクルを考慮して、実装型でインジェクトする。

abstract、@Binds は、インターフェースを介す場合の、 @InstallIn( ViewModelComponent::class)、 @ViewModelScoped は、 ViewModel に対してのインジェクトのパターン。


@Module
@InstallIn(ViewModelComponent::class)
abstract class RepositoryModule {

  @Binds
  @ViewModelScoped
  abstract fun bindRepository(impl: DefaultRepository): MainRepository
}

 

💉 Repository ← DataSource

Androidクラスのようなプロパティへのインジェクトとは違う @Module、@Provides を使ったコンストラクタインジェクトの Hilt基本的パターン。

SingletonComponent は、旧 ApplcationComponent で生存期間最長。


class DefaultRepository @Inject constructor(
  private val localDao: LocalDao,
  private val contentResolver: ContentResolver,
  private val sharedPreferences: SharedPreferences
) : MainRepository {


@Module
@InstallIn(SingletonComponent::class)
object DataSourceModule {

  @Provides
  @Singleton
  fun provideLocalDao(
    @ApplicationContext context: Context
  ): LocalDao {
    return LocalDao(context)
  }

 

💉 DataSource ← Context

Context は、 @ApplicationContext と @ActivityContext がすでに用意されているので区別しながらアノテーション1つのみで注入できる。これ便利。


@Module
@InstallIn(SingletonComponent::class)
object DataSourceModule {

  @Provides
  @Singleton
  fun provideLocalDao(
    @ApplicationContext context: Context
  ): LocalDao {
    return LocalDao(context)
  }

しかし、どの位置でも自在にインジェクトしようとするとコケる。


[Dagger/MissingBinding] @dagger.hilt.android.qualifiers.ActivityContext android.content.Context cannot be provided without an @Provides-annotated method.

@Module 直下の @Provides メソッドの引数で使うものですか。

 

build.gradle


buildscript {
  ext.versions = [
    "hilt"       : "2.41",
  ]
  dependencies {
    classpath "com.google.dagger:hilt-android-gradle-plugin:${versions.hilt}"
  }
}

apply plugin: "org.jetbrains.kotlin.kapt"
apply plugin: "dagger.hilt.android.plugin"

dependencies {
  implementation "com.google.dagger:hilt-android:${versions.hilt}"
  kapt "com.google.dagger:hilt-android-compiler:${versions.hilt}"

  androidTestImplementation  "com.google.dagger:hilt-android-testing:${versions.hilt}"
  kaptAndroidTest "com.google.dagger:hilt-compiler:${versions.hilt}"
  testImplementation "com.google.dagger:hilt-android-testing:${versions.hilt}"
  kaptTest "com.google.dagger:hilt-compiler:${versions.hilt}"
}

👉 Gradle Build Setup 

 

💉 まとめ

多少の流儀はあるけど、 Component 記述がなくなっただけでも記述量は大幅に削減できます。

alpha らしく、まだコンポーネント名など変わるんかもしれんが、ここも適宜修正させてもらいます。

👉 【MVVM】 Kotlin Flow で使える5つの利用パターン 
👉 skydoves/Pokedex: 🗡️ Android Pokedex using Hilt, Motion, Coroutines, Flow, Jetpack (Room, ViewModel) based on MVVM architecture. 
👉 Hilt and Dagger annotations cheat sheet - Android Developers - Medium 



KMM まとめ 速報 - Kotlin Multiplatform Mobile 【#ios | #android】

このページは随時更新していくページです。

まずは、2022年 Stable版リリースまで追っていきます。

開発時に使えるだろう記事をフォーカスしてまとめておきます。

連絡などは Twitter や Facebook の DM でどうぞ。

KMM まとめ 速報 ( Kotlin Multiplatform Mobile )【#ios | #android】



おすすめ

Googleは、この状況を改善するために、すべてのKotlinターゲットのための適切なマルチプラットフォームの成果物として、Composeランタイムを出荷すべきです。残念ながら、彼らのKotlinマルチプラットフォームの話は、コミュニティのニーズから数年遅れており、これがすぐに実現する見込みは非常に低い。

👉 Multiplatform Compose and Gradle module metadata abuse - Jake Wharton 

 

- New KMM library project wizard.
- Support for the new type of KMM library distribution: XCFramework.
- Enabled HMPP for new KMM projects.
- Support for explicit iOS targets declaration.
- Enabled KMM plugin wizards on non-Mac machines.
- Support for subfolders in the KMM module wizard.
- Support for Xcode Assets.xcassets file.
- Fixed the plugin classloader exception.
- Updated the CocoaPods Gradle Plugin template.
- Kotlin/Native debugger type evaluation improvements.
- Fixed iOS device launching with Xcode 13.

👉 KMM plugin releases | Kotlin 

クロスプラットフォームモバイル環境向け SDK の Kotlin Multiplatform Mobile(KMM)は、2020年8月にアルファ版として公開されました。

👉 アルファ版以降の KMM 新着情報 | The Kotlin Blog 

公式

👉 アルファ版以降の KMM 新着情報 | The Kotlin Blog 
👉 Kotlin Multiplatform Mobile がアルファ段階に移行 | The Kotlin Blog 
👉 Kotlin Multiplatform Mobile | Kotlin 

その他

👉 5分でわかる、Kotlin Multiplatform Mobile (KMM) 
👉 KMMでiOS・Android
を共通化しよう - dely tech blog 
👉 KMMというもう一つの選択肢 | bravesoft blog 
👉 Kotlin Multiplatform Mobile(KMM)がベータへ。コンカレント処理でのメモリリークフリー、iOSエコシステムとの連携強化など - Publickey 

実際に確認してみる

👉 AndroidStudio 利用する Java (JDK) の選択・設定の方法 
👉 Mac に Homebrew で OpenJDK11 を インストール する 

(このページは随時更新していくページです。)