Kotlin、Retrofit、RxJava封装REST API

作者: ImWiki | 来源:发表于2019-05-18 00:05 被阅读3次

    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 <T> Call<T>.rx(): Observable<T> {
        return Observable.create<T> {
            try {
                it.onNext(executeBody())
                it.onComplete()
            } catch (e: Exception) {
                it.onError(e)
            }
        }.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
    }
    
    fun <T> Call<T>.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<User>
    }
    

    使用

    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

        本文链接:https://www.haomeiwen.com/subject/pwnaaqtx.html