使用Retrofit+LiveData时的Error/Loading处理

目前还有很多项目使用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类中主要完成以下工作:

  1. 基于apiService创建Retofit,
  2. 通过EventListener处理loading状态
  3. 通过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主要工作:

  1. 提供API请求的调用方法, 并接受LiveData参数
  2. 继承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请求过程的最新状态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fundroid

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值