目前还有很多项目使用Retrofit2+LiveData进行API请求,LiveData在不像RxJava那样可以方便地进行Error处理,所以想基于LiveData封装一个工具类,对API请求中的Error/Loading等进行统一处理
HttpManager
open class HttpManager<T>(context: Context, serviceClass: Class<T>) {
private val BASE_URL: String = context.getString(R.string.wallet_api_url)
private var isLoading: MutableLiveData<Boolean>? = null
private var error: MutableLiveData<ErrorResponse>? = null
private val service = getRetrofit(
serviceClass,
BASE_URL,
getHttpClient(context)
)
fun init(
isLoading: MutableLiveData<Boolean>? = null,
error: MutableLiveData<ErrorResponse>? = null
):T {
this.isLoading = isLoading
this.error = error
return service
}
private fun createHeader(context: Context, request: Request): Request {
return request.newBuilder()
.addHeader("Accept", "application/json")
.build()
}
private fun getHttpClient(context: Context) : OkHttpClient {
val interceptor = Interceptor { chain ->
val response = chain.proceed(createHeader(context, chain.request()))
if(response.code() != ErrorCode.HTTP_OK_200.httpErrorCode) {
try {
val source = response.body()?.source()
source?.request(java.lang.Long.MAX_VALUE)
val bodyString = source?.buffer?.clone()?.readString(Charset.forName("UTF-8")).toString()
val errorBase = Gson().fromJson(bodyString, ErrorBase::class.java)
error?.postValue(ErrorResponse(response.code(), errorBase))
} catch (e: Exception) {
error?.postValue(ErrorResponse(response.code(), ErrorBase("Unknown Error", null)))
}
}
response
}
return OkHttpClient.Builder()
.addInterceptor(interceptor)
.addInterceptor(getLoggingInterceptor())
.eventListener(object: EventListener(){
override fun callStart(call: Call) {
isLoading?.postValue(true)
super.callStart(call)
}
override fun callEnd(call: Call) {
isLoading?.postValue(false)
super.callEnd(call)
}
})
.readTimeout(5, TimeUnit.SECONDS)
.connectTimeout(5, TimeUnit.SECONDS)
.build()
}
private fun getLoggingInterceptor(): HttpLoggingInterceptor {
val logging = HttpLoggingInterceptor()
if (BuildConfig.DEBUG) {
logging.level = HttpLoggingInterceptor.Level.BODY
} else {
logging.level = HttpLoggingInterceptor.Level.NONE
}
return logging
}
private fun getRetrofit(serviceClass: Class<T>, baseUrl: String, httpClient: OkHttpClient) : T {
val retrofit: Retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(getConverter())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(httpClient)
.build()
return retrofit.create(serviceClass)
}
private fun getConverter() : Converter.Factory {
return GsonConverterFactory.create(GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.create())
}
}
HttpManager类中主要完成以下工作:
- 基于apiService创建Retofit,
- 通过EventListener处理loading状态
- 通过Interceptor处理Error
ExampleApi
class ExampleApi(context: Context ) : HttpManager< ExampleApi. ExampleService (
context, ExampleService::class.java) {
interface ExampleService {
@POST("/user/setting")
fun setting(): Call<ExampleResponse>
}
fun setting(responseLiveData: MutableLiveData<ExampleResponse>,
isLoading: MutableLiveData<Boolean>?, error: MutableLiveData<ErrorResponse>?) {
GlobalScope.launch {
init(isLoading, error)
.setting()
.enqueue(object: Callback<ExampleResponse> {
override fun onFailure(call: Call<ExampleResponse>,
t: Throwable) {
//error处理由HttpManager负责,故此处 nothing to do
}
override fun onResponse(call: Call<ExampleResponse>,
response: retrofit2.Response<ExampleResponse>) {
if (response.isSuccessful) {
responseLiveData.postValue(response.body())
}
}
})
}
}
data class ExampleResponse(
val hoge: Boolean,
val fuga: String
)
}
ExampleApi主要工作:
- 提供API请求的调用方法, 并接受LiveData参数
- 继承HttpManager,通过Retrofit进行Api请求
Activity
val response = MutableLiveData<ExampleApi.ExampleResponse>()
val error = MutableLiveData<ErrorResponse>()
val isLoading = MutableLiveData<Boolean>()
WalletUserApi(this).setting(response, isLoading, error)
response.observeForever { result ->
Toast.makeText(this, "response: $result", Toast.LENGTH_SHORT ).show()
}
error.observeForever { result ->
Toast.makeText(this, "response: $result", Toast.LENGTH_SHORT ).show()
}
isLoading.observeForever {
//プログレスダイアログ出したりDatabindingでいい感じにする
}
Activity做的事情比较简单,调用Api类并传入LiveData即可。
LIveData可以放入ViewModel管理,在Activity范围内所有的Fragment或者自定义View等可以方便及时地订阅Api请求过程的最新状态。