[Android] Retrofit+OkHttpを使ってAPI通信を安定化させるベストプラクティス

スポンサーリンク

はじめに

Android開発でAPI通信をするなら、ほとんどの人が使っているであろうRetrofitOkHttp
ただ「とりあえず動く」レベルで書いていると、タイムアウトや再試行、ログ管理あたりで後々つまづきやすいです。
今回は、Retrofit+OkHttpを組み合わせて、安定して通信できるようにするための基本構成を紹介します。

依存関係を追加する


implementation "com.squareup.retrofit2:retrofit:2.11.0"
implementation "com.squareup.retrofit2:converter-gson:2.11.0"
implementation "com.squareup.okhttp3:okhttp:4.12.0"
implementation "com.squareup.okhttp3:logging-interceptor:4.12.0"

Retrofitの最新安定版は2.11系、OkHttpは4.12系で、Android 14〜16でも安定動作しています。
ログ出力のためにlogging-interceptorも追加しておくと便利です。

OkHttpClientの基本設定

まずはOkHttpのインスタンスを安全に構成します。


object ApiClient {

    private val loggingInterceptor = HttpLoggingInterceptor().apply {
        level = HttpLoggingInterceptor.Level.BODY
    }

    private val client = OkHttpClient.Builder()
        .connectTimeout(10, TimeUnit.SECONDS)
        .readTimeout(20, TimeUnit.SECONDS)
        .writeTimeout(20, TimeUnit.SECONDS)
        .addInterceptor(loggingInterceptor)
        .retryOnConnectionFailure(true)
        .build()

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

    val service: ApiService = retrofit.create(ApiService::class.java)
}

ここでのポイントは以下の4つです。

  • connectTimeout / readTimeout / writeTimeoutを明示的に指定
  • retryOnConnectionFailure(true)で再試行を有効化
  • HttpLoggingInterceptorで通信ログを出力
  • OkHttpClientobjectで1つにまとめてシングルトン化

これでアプリ全体から安全に共通のHTTPクライアントを利用できます。

APIインターフェースを定義


interface ApiService {

    @GET("users")
    suspend fun getUsers(): Response<List<User>>

    @POST("login")
    suspend fun login(@Body request: LoginRequest): Response<LoginResponse>
}

Retrofitでは、HTTPメソッドごとにアノテーションで指定するだけ。
Kotlin Coroutines対応なので、suspend関数で書くのが今の主流です。

API呼び出しの実装例


viewModelScope.launch {
    try {
        val response = ApiClient.service.getUsers()
        if (response.isSuccessful) {
            val users = response.body()
            Log.d("API", "ユーザー取得成功: ${users?.size}件")
        } else {
            Log.e("API", "エラー: ${response.code()}")
        }
    } catch (e: IOException) {
        Log.e("API", "ネットワークエラー: ${e.message}")
    } catch (e: HttpException) {
        Log.e("API", "HTTPエラー: ${e.code()}")
    }
}

通信は基本的にtry-catchで包んでおくのが鉄則です。
サーバーエラーやタイムアウトが起きても、アプリを落とさずに済みます。

よくある失敗パターン

① Contextを直接使ってしまう

ViewModelやRepositoryの中でContextを直接参照するのは危険です。
RetrofitはContextに依存しない設計にしておくのがベターです。

② OkHttpClientを毎回生成している

Retrofit.Builder()OkHttpClient.Builder()を都度生成していると、無駄なスレッドやメモリを消費します。
シングルトンパターンで1回だけ作るようにしましょう。

③ タイムアウトが長すぎる/短すぎる

APIの性質に合わせて調整することが重要です。
5〜10秒以内にレスポンスがないなら、再試行させたほうがUX的にも良いことが多いです。

OS16対応ポイント

Android 16ではネットワークアクセス制限が一部強化され、
HTTP/3(QUIC)対応サーバーへの接続でタイムアウト検知の挙動が変わります。
Retrofit 2.11+OkHttp 4.12以降では自動的に対応しているので、
特別な実装変更は不要です。
ただし、古いライブラリを使っている場合はログが出なくなることもあるため、
HttpLoggingInterceptorの更新は忘れずに行いましょう。

まとめ

  • OkHttpClientはシングルトンで管理
  • ログ出力とタイムアウト設定を明示する
  • 例外処理(IOException / HttpException)でクラッシュ防止
  • Android 16でも安定動作する最新バージョンを利用

Retrofit+OkHttpは非常に強力ですが、
設定を一歩間違えると「動くけど不安定」になりがちです。
基本の設定を固めておくと、後から機能を追加しても壊れにくくなるのでおすすめです。

コメント

タイトルとURLをコピーしました