Kotlin、Retrofit、RxJava優雅実現REST API要求

3405 ワード

Retrofitは非常に強力なネットワークリクエスト案で、公式にもadapter-rxjava2ライブラリがありますが、使いにくいと思いますが、実はKotlinの拡張属性で非常に使いやすい案を実現できます.
REST API
各エンジニア定義のREST APIは異なりますが、基本的な考え方は同じです.
  • 異常がなければ、オブジェクトを返すか、空のオブジェクトを返すか.
  • 要求にエラーが発生した場合、HTTPのstatusCodeは400より大きく、要求が正常である限り2 xxである.
  • 要求エラーが発生した場合、errorBodyはエラーコードおよびエラー情報を返す.
  • {
        "error_code":1101,
        "error":"     "
    }
    

    依存の追加
    dependencies {
        implementation 'com.squareup.retrofit2:retrofit:2.4.0'
        implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
        implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
    }
    

    NetworkException.ktの作成
    class NetworkException : Exception() {
        var error_code: String = ""
        var error: String? = ""
        override val message: String?
            get() = error
    }
    

    ファイルを作成_Call.kt
    fun  Call.rx(): Observable {
        return Observable.create {
            try {
                it.onNext(executeBody())
                it.onComplete()
            } catch (e: Exception) {
                it.onError(e)
            }
        }.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
    }
    
    fun  Call.executeBody(): T {
        try {
            val response = execute()
            if (response.isSuccessful) {
                return response.body()!!
            } else if (response.errorBody() != null) {
                val text = response.errorBody()!!.string()
                val json = JSONObject(text)
                val code = json.getString("error_code")
                val error = json.getString("error")
                val exception = NetworkException()
                exception.error_code = code
                exception.error = error
                throw exception
            } else {
                throw Exception("    ")
            }
        } catch (e: Exception) {
            if (e !is NetworkException) {
                when (e) {
                    is InterruptedIOException -> throw Exception("      ,     ")
                    is JSONException -> throw Exception("      ,     ")
                    is IOException -> throw Exception("       ,     ")
                    else -> throw Exception("    ")
                }
            }
            throw e
        }
    }
    

    APIインタフェースの定義
    interface AccountApiService {
        @FormUrlEncoded
        @POST("/account/login/phone")
        fun loginPhone(@Field("phone") phone: String,@Field("code") code: String): Call
    }
    

    使用
    val retrofit = Retrofit.Builder().baseUrl("http://127.0.0.1:8080")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    val accountApiService = retrofit.create(AccountApiService::class.java)
    

    同期要求
    try {
      val result = accountApiService.loginPhone("18888888888", "1234").executeBody()
      println(JSON.toJSONString(result))
    } catch (e: Exception) {
      println(e.message)
    }
    

    RxJava非同期要求
    accountApiService.loginPhone("18888888888", "1234").rx().subscribe({
      println(JSON.toJSONString(it))
    },{
      println(e.message)
    })
    

    まとめ
    このソリューションの最大の特徴は、CallメソッドをRxJavaに移行できることであり、同期リクエストがある場合もあれば、非同期リクエストがある場合もあり、複数のAPIを繰り返し定義する必要はありません.