LoginSignup
24
20

More than 5 years have passed since last update.

Android Retrofit2とMoshi

Last updated at Posted at 2019-03-04

はじめに

Androidアプリの開発でAPI通信を行う際、Retrofitを使うことが多いと思います。
取得したjsonをパースする際にGsonを利用してもいいのですが、Kotlinと相性が悪いです。
そこで、Kotlinのclassへのサポートを提供しているSquareのMoshiを使ってjsonをパースしました。

  • Kotlin 1.3.21
  • Retrofit 2.5.0
  • Moshi 1.5.0
  • Okhttp 3.13.1
app/build.gradle
// ...

dependencies {

    // ...

    // Retrofit
    def retrofit_version = '2.5.0'
    implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
    implementation "com.squareup.retrofit2:converter-moshi:$retrofit_version"

    // Moshi
    def moshi_version = '1.5.0'
    implementation "com.squareup.moshi:moshi:$moshi_version"
    implementation "com.squareup.moshi:moshi-kotlin:$moshi_version"

    // Okhttp
    def okhttp_version = '3.13.1'
    implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
    implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_version"
}

受け取るJson

APIを叩いた時に受け取るJsonはこちらを想定しています。

companies.json
{
    "companies": [
        {
            "id": "001",
            "name": "会社1",
            "img": "https://kaisya1"},
        {
            "id": "002",
            "name": "会社2",
            "img": "https://kaisya2"
        }
    ]
}

data class

パースしてオブジェクト化するためのclassがこちらです。

Company.kt
data class Company (val id: String, val name: String, val img: String)
Companies.kt
data class Companies (val companies: List<Company>)

Interface

Retrofit2のinterfaceはこちらです。

CompanyApiInterface.kt
interface CompanyApiInterface {
    @GET("companyList")
    fun getCompanyList(): Call<Companies>
}

実装例

API通信を行なうclassをこんな感じで実装してみました。

CompanyRepository.kt
class CompanyRepository(url: String) {

    private var retrofit: Retrofit

    init {
        val moshi = Moshi.Builder()
                .add(KotlinJsonAdapterFactory())
                .build()

        this.retrofit = Retrofit.Builder()
                .baseUrl(url)
                .addConverterFactory(MoshiConverterFactory.create(moshi))
                .client(getClient())
                .build()
    }

    fun getCompanies(): Response<Companies> {
        val service = this.retrofit.create(ArticleApiInterface::class.java)
        return service.getCompanyList().execute()
    }

    private fun getClient(): OkHttpClient {
        return OkHttpClient
                .Builder()
                .connectTimeout(120, TimeUnit.SECONDS)
                .readTimeout(120, TimeUnit.SECONDS)
                .addInterceptor(HttpLoggingInterceptor().apply {
                    level = HttpLoggingInterceptor.Level.BODY
                })
                .build()
    }
}

利用する際はこの様に利用します。

private fun load(){
    try{
        val companyRepository = CompanyRepository("https://hoge")
        val response = companyRepository.getCompanies()
            if(response.isSuccessful){
                // 成功
            }else{

            }
    }catch (t: Throwable){

    }
}

つまったとこ

Moshiと全く関係のない箇所でつまりました。
Retrofitのinterfaceをこの様に作成していました。

@GET("companyList")
fun getCompanyList(): Call<List<Company>>

こう書いてしまうとAPI通信は成功しますが、
Jsonのcompaniesのキーに紐づく変数がなくパースに失敗します↓。
retrofit expected begin_array but was begin_object at line 1 column 2 path $
よってこのdata classを作成することで解決しました。

data class Companies (val companies: List<Company>)

よりよい解決方法をご存知の方は教えていただけると幸いです!

24
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
20