美文网首页
Retrofit 2.0 Gson解析数据的特殊处理

Retrofit 2.0 Gson解析数据的特殊处理

作者: 咖啡苏克 | 来源:发表于2018-08-14 17:24 被阅读0次

    Retrofit 2.0的使用及封装见 Retrofit 2.0的封装与异常处理

    开发过程中有时会遇到这种需求,即后台返回的数据,我们需要做进一步处理,比如字段的替换、筛选或者排序,结合上一篇Retrofit 2.0的使用,通常情况下我们在onResponse回调后获得后台返回的model,然后再执行一些特殊处理,如果是耗时操作,我们还需要开个线程...这种方式既不灵活也不优雅。

    我们能不能在http获取数据后,onResponse回调之前,即Retrofit2.0 Gson解析时“顺便”把数据处理了?这样既保证了在子线程又能保持onResponse回调中代码的清爽。

    下面看我的解决方案:

    interface ResponseConverter <T>{
        fun onGsonResponseBody(value: T): T
    }
    
    1. 先定义一个接口,如过某个请求需要特殊处理,实现该接口并在onGsonResponseBody回调中进行处理,这里不需要考虑线程,因为该回调本身就是在子线程中执行的,这个后面会讲,示例代码如下:
    class MarketResponseConverter : ResponseConverter<HttpResponse<Market>> {
        override fun onGsonResponseBody(httpResponse: HttpResponse<Market>): HttpResponse<Market>{
            httpResponse.msg = "this is test message"
            return httpResponse
        }
    }
    
    1. 再定义一个注解,该注解是加到Retrofit2.0定义的请求上,好让GsonResponseBodyConverter知道我这个请求需要单独做处理,注解的属性即上面我们定义的ResponseConverter的Class
    @Target(AnnotationTarget.FUNCTION)
    @Retention(AnnotationRetention.RUNTIME)
    annotation class ResponseProcess(val clazz: KClass<out ResponseConverter<*>>)
    
    interface ApiService {
        @POST("market/getMarket")
        @ResponseProcess(MarketResponseConverter::class)
        fun getMarket(): Call<HttpResponse<Market>>
    
    1. 重点,自定义GsonConverterFactoryGsonResponseBodyConverter , Gson解析完后不直接返回数据,而是判断请求是否有加ResponseProcess注解,如果有ResponseProcess注解则通过反射直接获取该注解属性的ResponseConverter数据处理类,执行onGsonResponseBody后再返回数据。
    class CustomGsonConverterFactory(val gson: Gson) : Converter.Factory() {
        companion object {
            fun create(): CustomGsonConverterFactory {
                return create(Gson())
            }
    
            private fun create(gson: Gson?): CustomGsonConverterFactory {
                if (gson == null) throw NullPointerException("gson == null")
                return CustomGsonConverterFactory(gson)
            }
        }
    
        override fun responseBodyConverter(type: Type?, annotations: Array<out Annotation>?, retrofit: Retrofit?): Converter<ResponseBody, *>? {
            /** 直接将annotations作为参数传递给CustomGsonResponseBodyConverter**/
            return CustomGsonResponseBodyConverter(gson, annotations, gson.getAdapter(TypeToken.get(type)))
        }
    
        override fun requestBodyConverter(type: Type?, parameterAnnotations: Array<out Annotation>?,
                                          methodAnnotations: Array<out Annotation>?, retrofit: Retrofit?): Converter<*, RequestBody>? {
            return CustomGsonRequestBodyConverter(gson, gson.getAdapter(TypeToken.get(type)))
        }
    }
    
    class CustomGsonResponseBodyConverter<T>(private val gson: Gson, private val annotations: Array<out Annotation>?, private val adapter: TypeAdapter<T>) : Converter<ResponseBody, T> {
    
        override fun convert(value: ResponseBody): T {
            val response = value.string()
            val httpStatus = gson.fromJson(response, HttpStatus::class.java)
            /** 本节无关,异常统一处理,见上篇《Retrofit 2.0的封装与异常处理》**/
            if (!httpStatus.isSuccess()) {
                value.close()
                throw ApiException(httpStatus.code, httpStatus.msg)
            }
            val contentType = value.contentType()
            val charset = contentType?.charset(UTF_8) ?: UTF_8
            val inputStream = ByteArrayInputStream(response.toByteArray())
            val reader = InputStreamReader(inputStream, charset!!)
            val jsonReader = gson.newJsonReader(reader)
    
            value.use { _ ->
                val result = adapter.read(jsonReader)
                if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
                    throw JsonIOException("JSON document was not fully consumed.")
                }
    
                /** 遍历annotations判断该请求是否存在ResponseProcess注释 **/
                if (annotations != null) {
                    for (annotation: Annotation in annotations) {
                        if (annotation is ResponseProcess) {
                            @Suppress("UNCHECKED_CAST")
                            /** 反射获取ResponseConverter的实例 **/
                            val instance = annotation.clazz.createInstance() as ResponseConverter<T>
                            /** 数据经过onGsonResponseBody处理后再返回 **/
                            return instance.onGsonResponseBody(result)
                        }
                    }
                }
                return result
            }
        }
    }
    

    测试后你会发现该请求的HttpResponse的msg已经被我们替换成"this is test message"。

    相关文章

      网友评论

          本文标题:Retrofit 2.0 Gson解析数据的特殊处理

          本文链接:https://www.haomeiwen.com/subject/ijcvbftx.html