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

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

  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
    }

    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主要工作:

  1. 提供API请求的调用方法, 并接受LiveData参数
  2. 继承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,Retrofit,Android,Retrofit)