Kotlin、Retrofit、RxJava封装REST API
2019-05-18 本文已影响3人
ImWiki
Retrofit是非常强大的网络请求方案,虽然官方也有adapter-rxjava2
库,但是我觉得并不好用,其实通过Kotlin的拓展属性即可实现非常好用的方案。
REST API
每个工程师定义的REST API都不太一样,但是基本的思路都是一样。
- 如果没有出现异常就是返回对象或者返回空对象;
- 如果请求出现错误,HTTP的statusCode是大于400,只有请求正常才是2xx。
- 如果请求出错,那么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。