LoginSignup
18
25

More than 5 years have passed since last update.

Retrofit+RxJava+kotlinを使ったAPIコール処理を作ってみた

Last updated at Posted at 2018-09-28
1 / 2

Retrofit+RxJava+kotlinを使ったAPIコール処理を作ってみた

はじめに

AndroidでWebAPIを呼び出す処理を行う場合、いろいろ方法がありますが、今回はRetrofit+RxJavaを使用して簡単サンプルアプリを作成してみます。

Kotlinの導入

Android Studio 3.2を使用しているのでkotlinの導入は自動化されています。

image.png

include Kotlin support にチェックをつけます。
そのままNextと進んで最終的に新規プロジェクトを作成すると

build.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    ext.kotlin_version = '1.2.71'
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.2.0'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
app/build.gradle
apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

android {
    :
}

dependencies {
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    :
    :
}

のように設定されるので、Kotlinが使用可能となります。

RxJavaの導入

app/build.gradle
    implementation "io.reactivex:rxjava:1.3.8"
    implementation "io.reactivex:rxandroid:1.2.1"

Retrofit2の導入

app/build.gradle
    implementation 'com.squareup.retrofit2:retrofit:2.4.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
    implementation 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
    implementation 'com.squareup.okhttp3:logging-interceptor:3.9.1'

APIを呼び出してみる

皆様お世話になっている定番の郵便番号から住所を検索できるAPI
http://zipcloud.ibsnet.co.jp/api/search
を使用しました。
ZipCloudさんありがとうございます :bow_tone1:

ZipResponse(Response用のEntity オブジェクト)

APIを呼び出したときのレスポンスを格納するものになります。

ZipResponse.kt
data class ZipResponse(
        var message: String? = null,
        var status: Int? = null,
        var results: ArrayList<Address> = ArrayList()
)
Address.kt
data class Address(
        var address1: String ?= null, //"address1": "北海道",
        var address2: String ?= null, //"address2": "美唄市",
        var address3: String ?= null, //"address3": "上美唄町協和",
        var kana1: String ?= null, //"kana1": "ホッカイドウ",
        var kana2: String ?= null, //"kana2": "ビバイシ",
        var kana3: String ?= null, //"kana3": "カミビバイチョウキョウワ",
        var prefcode: String ?= null, //"prefcode": "1",
        var zipcode: String ?= null //"zipcode": "0790177"
)

ApiClientを作成

ApiClient.kt
interface ApiClient {
    @GET("api/search")
    fun getZipCode(@Query("zipcode") zipcode: String): Observable<ZipResponse>
}

今回は1つのAPIコールだけですが、複数ある場合は、ここにAPI毎のメソッドを定義していきます
もちろん、@GET@POST、その他もサポートされています。
https://square.github.io/retrofit/

ApiClientManagerを作成

ApiClientManager.kt
open class ApiClientManager {
    companion object {
        private const val ENDPOINT = "http://zipcloud.ibsnet.co.jp/"
        private val TAG = ApiClientManager::class.simpleName

        val apiClient: ApiClient
            get() = Retrofit.Builder()
                    .client(getClient())
                    .baseUrl(ENDPOINT)
                    .addConverterFactory(GsonConverterFactory.create(Gson()))
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    .build()
                    .create(ApiClient::class.java)

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

呼び出してみる

MainActivity.kt

    private val compositeSubscription = CompositeSubscription()

    override fun onCreate(savedInstanceState: Bundle?) {
        binding.buttonSubmit.setOnClickListener { _ ->
            val zipcode = "0790177"
            compositeSubscription.clear()
            compositeSubscription.add(
                        ApiClientManager.apiClient.getZipCode(zipcode)
                                .subscribeOn(Schedulers.io())
                                .observeOn(AndroidSchedulers.mainThread())
                                .doOnNext {
                                    Log.d(TAG, "response=$it")
                                    binding.textViewResponse.text = Gson().toJson(it)
                                }
                                .doOnError {
                                }
                                .doOnCompleted {
                                }
                                .subscribe())
        }
    }

    override fun onDestroy() {
        compositeSubscription.clear()
        super.onDestroy()
    }

onDestroy()compositeSubscription.clear() を呼ぶことでActivity破棄時に未処理のsubscribeを破棄できます

 D/OkHttp: --> GET http://zipcloud.ibsnet.co.jp/api/search?zipcode=0790177
 D/OkHttp: --> END GET
 D/OkHttp: <-- 200 OK http://zipcloud.ibsnet.co.jp/api/search?zipcode=0790177 (598ms)
 D/OkHttp: Content-Type: text/plain; charset=utf-8
 D/OkHttp: X-Cloud-Trace-Context: fbdffd1b9974a560f3a891322b559248
 D/OkHttp: Date: Fri, 28 Sep 2018 14:07:26 GMT
 D/OkHttp: Server: Google Frontend
 D/OkHttp: Content-Length: 854
 D/OkHttp: {
 D/OkHttp:  "message": null,
 D/OkHttp:  "results": [
 D/OkHttp:      {
 D/OkHttp:          "address1": "北海道",
 D/OkHttp:          "address2": "美唄市",
 D/OkHttp:          "address3": "上美唄町協和",
 D/OkHttp:          "kana1": "ホッカイドウ",
 D/OkHttp:          "kana2": "ビバイシ",
 D/OkHttp:          "kana3": "カミビバイチョウキョウワ",
 D/OkHttp:          "prefcode": "1",
 D/OkHttp:          "zipcode": "0790177"
 D/OkHttp:      },
 D/OkHttp:      {
 D/OkHttp:          "address1": "北海道",
 D/OkHttp:          "address2": "美唄市",
 D/OkHttp:          "address3": "上美唄町南",
 D/OkHttp:          "kana1": "ホッカイドウ",
 D/OkHttp:          "kana2": "ビバイシ",
 D/OkHttp:          "kana3": "カミビバイチョウミナミ",
 D/OkHttp:          "prefcode": "1",
 D/OkHttp:          "zipcode": "0790177"
 D/OkHttp:      },
 D/OkHttp:      {
 D/OkHttp:          "address1": "北海道",
 D/OkHttp:          "address2": "美唄市",
 D/OkHttp:          "address3": "上美唄町",
 D/OkHttp:          "kana1": "ホッカイドウ",
 D/OkHttp:          "kana2": "ビバイシ",
 D/OkHttp:          "kana3": "カミビバイチョウ",
 D/OkHttp:          "prefcode": "1",
 D/OkHttp:          "zipcode": "0790177"
 D/OkHttp:      }
 D/OkHttp:  ],
 D/OkHttp:  "status": 200
 D/OkHttp: }
 D/OkHttp: <-- END HTTP (854-byte body)
D/MainActivity: response=ZipResponse(message=null, status=200, results=[Address(address1=北海道, address2=美唄市, address3=上美唄町協和, kana1=ホッカイドウ, kana2=ビバイシ, kana3=カミビバイチョウキョウワ, prefcode=1, zipcode=0790177), Address(address1=北海道, address2=美唄市, address3=上美唄町南, kana1=ホッカイドウ, kana2=ビバイシ, kana3=カミビバイチョウミナミ, prefcode=1, zipcode=0790177), Address(address1=北海道, address2=美唄市, address3=上美唄町, kana1=ホッカイドウ, kana2=ビバイシ, kana3=カミビバイチョウ, prefcode=1, zipcode=0790177)])

最後に

CompositeSubscriptionが便利です。
AsyncTaskを使用した場合などに比べ、シンプルにコードが書けると思います。

ソースは
https://github.com/motomiya326/retrofit-example
にあるのでご自由にお使いください。

18
25
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
18
25