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

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"。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,539评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,594评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,871评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,963评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,984评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,763评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,468评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,850评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,002评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,144评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,823评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,483评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,026评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,150评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,415评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,092评论 2 355

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,190评论 25 707
  • 简介 刚接触Retrofit的时候,就写了一篇简单的使用介绍:Retrofit 2.0基本使用方法,算是对Retr...
    Whyn阅读 2,848评论 4 24
  • 网上有个段子说:”5G时代都快来了,我才刚用上3G,我是不是与时代脱轨了!“我想说“是”别人都进入智能时代了,你还...
    芳芳_d747阅读 185评论 0 0
  • 晨起,不想煮早餐,有点想放弃,想起自己动的那个想吃的念头,强迫自己去行动,于是一碗瑶柱淮山粥出来了。 上午上了两节...
    CherryHuang阅读 182评论 0 1