はじめに
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>)
よりよい解決方法をご存知の方は教えていただけると幸いです!