💬

ゆめみ社のAndroidインターンに参加してきたので学んだことをまとめておく(サーバと通信編)

2022/09/07に公開

ゆめみ社の Android インターンに参加しました。
なかなかにありがたい経験をさせてもらえたので、アウトプットします 👍

  • 基本的には課題を進めていく 🚶
  • 課題は AndroidView で開発する前提になっていたが、Jetpack Compose の方が得意という旨を伝えると、Compose を使って UI を作っていくことに。柔軟に対応していただくことができた。感謝 😊

サーバと通信

参考:
なかなかリアルタイムに更新された記事
https://qiita.com/hiesiea/items/d1d8fff1d4a4ed12fbfb
公式ドキュメント
https://square.github.io/retrofit/

インターンでは途中までは実際には通信はしないメソッドを使って開発を進め、ある程度開発が進んだところで実際にモックサーバに対して通信を行うといった手順で実装しました。

Android の通信処理

Android の通信といえばRetrofitです。OkHttpというライブラリのラッパーでインターフェースを定義するだけでいい感じにサーバにアクセスしてくれる優れものです。

記事を参考にコピペ

こちらを参考に進めていきます。

サーバからは以下のようなレスポンスが返ってきます。

サーバからのレスポンス例
{
  "weather":"sunny",
  "maxTemp":10,
  "minTemp":-5,
  "date":"2022-08-31"
}

これを Retrofit で受け取るためには主に以下のステップが必要です。

  1. サーバに何を渡して何を受け取るかを定義するサービスインターフェースを定義
  2. サービスインスタンスを作成
  3. サービスインスタンス.メソッド()で API を呼び出し

なおせっかく DI について学んだばっかだったのでクライアントインスタンスを DI で取得してこようと言うことになりました。(学んだことが早速実践できて嬉しいかった 😊)

1. 天気を取得できるサービスインターフェース

interface WeatherService {
  @GET("weather")
  suspend fun getWeather(): Response<FetchWeatherResult>
}

// レスポンスデータを表すクラス
data class FetchWeatherResult(
  val weather: String,
  val maxTemp: Int,
  val minTemp: Int,
  val date: String,
)

2. クライアントインスタンスをDIで取得
@Module
@InstallIn(SingletonComponent:class)
object RetrofitModule{
  @Singleton
  @Provides
  fun provideWeatherService(
    retrofit: Retrofit,
  ):WeatherService{
    return retrofit.create(WeatherService::class)
  }
    @Singleton
    @Provides
    fun provideRetrofit(
        client: OkHttpClient,
        moshi: Moshi,
    ): Retrofit {
        return Retrofit.Builder()
            .baseUrl(/* モックサーバのURL */)
            .client(client)
            .addConverterFactory(MoshiConverterFactory.create(moshi))
            .build()
    }
    @Singleton
    @Provides
    fun provideOkHttpClient(): OkHttpClient {
        val logging = HttpLoggingInterceptor {
            // Timber.tag("OkHttp").d(it)
            Log.d("http-log", "$it")
        }
        logging.setLevel(HttpLoggingInterceptor.Level.BASIC)
        return OkHttpClient.Builder()
            .addInterceptor(logging)
            .addInterceptor(
                Interceptor { chain ->
                    val request = chain.request()
                    val response: Response = chain.proceed(request)
                    if (response.code == 500) {
                        throw UnexpectedResponseException()
                    }
                    return@Interceptor response
                }
            )
            .build()
    }

    @Singleton
    @Provides
    fun provideMoshi(): Moshi {
        return Moshi.Builder()
            .add(KotlinJsonAdapterFactory())
            .build()
    }
}

インターフェースを渡したらそれを実装したクラスが返ってくる(retrofit.create(WeatherService::class))のは中身どうなってるんだろうとか思ったりしました。

あと、反省としては、これ以前の課題で JSON のパースに KotlinSerialization を使っていたので Moshi ではなく KotlinSerialization を使ってみたらもっといい感じになったのかもってことです 😔

3. サービスインスタンスを呼び出す
val fetchRes = withContext(Dispatchers.IO){
  weatherService.getWeather()
}

Retrofit 自体はあっさりとおわって使いやすい印象でした。

また今まで学んできた DI やアーキテクチャ周りの話を実感できました!

インターンアウトプットシリーズ一覧

Discussion