Kotlin、Retrofit、RxJava优雅实现REST API请求

Retrofit是非常强大的网络请求方案,虽然官方也有adapter-rxjava2库,但是我觉得并不好用,其实通过Kotlin的拓展属性即可实现非常好用的方案。

REST API

每个工程师定义的REST API都不太一样,但是基本的思路都是一样。

  1. 如果没有出现异常就是返回对象或者返回空对象;
  2. 如果请求出现错误,HTTP的statusCode是大于400,只有请求正常才是2xx。
  3. 如果请求出错,那么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。

 

你可能感兴趣的:(Kotlin、Retrofit、RxJava优雅实现REST API请求)