使用Retrofit+LiveData时的Error/Loading处理
16lz
2021-01-26
目前还有很多项目使用Retrofit2+LiveData进行API请求,LiveData在不像RxJava那样可以方便地进行Error处理,所以想基于LiveData封装一个工具类,对API请求中的Error/Loading等进行统一处理
HttpManager
open class HttpManager(context: Context, serviceClass: Class) { private val BASE_URL: String = context.getString(R.string.wallet_api_url) private var isLoading: MutableLiveData? = null private var error: MutableLiveData? = null private val service = getRetrofit( serviceClass, BASE_URL, getHttpClient(context) ) fun init( isLoading: MutableLiveData? = null, error: MutableLiveData? = 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, 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 } fun setting(responseLiveData: MutableLiveData, isLoading: MutableLiveData?, error: MutableLiveData?) { GlobalScope.launch { init(isLoading, error) .setting() .enqueue(object: Callback { override fun onFailure(call: Call, t: Throwable) { //error处理由HttpManager负责,故此处 nothing to do } override fun onResponse(call: Call, response: retrofit2.Response) { 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()val error = MutableLiveData()val isLoading = MutableLiveData()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请求过程的最新状态。
更多相关文章
- Android(安卓)web services8 参数介绍
- cocos2dx中利用xcode 调用java中的函数
- Android中的Java与JavaScript方法互调
- android baseadapter的getview调用两次
- ArcGIS for Android示例解析之GP服务调用-----ViewShed
- Android(安卓)day_11-2 (服务)
- android RecyclerView局部刷新
- Android(安卓)cookies正确的更新方式
- Android(安卓)service跨进程调用和启动检查