Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

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

by motomiya326
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
にあるのでご自由にお使いください。

motomiya326
リモート開発、在宅勤務を特色とするシステム開発会社ローラハウスの業務執行社員として勤務しております。 ロックバンドのベーシストとしても現在活動中のロックプログラマーです。 Web系システム、スマートフォンアプリの開発のご用命はお気軽にどうぞ。
http://laurahouse.net
laurahouse
北海道を拠点にしてリモートワークでのスマートフォンアプリの開発を得意とするエンジニアによる技術者集団です。スマートフォンアプリの開発のご用命はお気軽に!
http://laurahouse.net
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした