Android

retrofit 同时支持 xml 和 json

retrofit 解析 json 是很简单的,但是,偶尔,只是偶尔,你也可能遇到解析 xml 的需求,而且最怕的是不同的接口返回的类型不一样,一个返回 json 一个 返回 xml,如何兼容?使用两个 retrofit 实例还是?本文将介绍一种更简单的办法,自定义 convert

平时,我们可能这样写代码:

Retrofit.Builder()
    .baseUrl(baseUrl)
    .addConverterFactory(GsonConverterFactory.create())
    .client(client)
    .build()

这里 GsonConverterFactory.create() 指定了使用 Gson 解析数据,我们完全可以自定义一个 convert ,类似这样:

import androidx.annotation.NonNull
import okhttp3.ResponseBody
import retrofit2.Converter
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.converter.simplexml.SimpleXmlConverterFactory
import top.kpromise.utils.IJson.getGson
import java.lang.reflect.Type

class SmartConverter : Converter.Factory() {
    private val xmlFactory: Converter.Factory = SimpleXmlConverterFactory.create()
    private val jsonFactory: Converter.Factory = GsonConverterFactory.create(getGson())
    override fun responseBodyConverter(@NonNull type: Type,
                                       annotations: Array<Annotation>,
                                       @NonNull retrofit: Retrofit): Converter<ResponseBody, *>? {
        for (annotation in annotations) {
            if (annotation !is ContentType) {
                continue
            }
            val value = annotation.value
            if (DataType.XML == value) {
                return xmlFactory.responseBodyConverter(type, annotations, retrofit)
            }
        }
        return jsonFactory.responseBodyConverter(type, annotations, retrofit)
    }

    companion object {
        fun create(): SmartConverter {
            return SmartConverter()
        }
    }
}

注解类 ContentType.kt 是这样子的:

@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
annotation class ContentType(val value: DataType = DataType.JSON) {

}

enum class DataType(private val contentType: String) {

    JSON("json"),
    XML("xml");

    fun contentType(): String {
        return contentType
    }
}

在需要的接口上可以这样子:

@GET("/xxx/xxx")
@ContentType(DataType.XML)
fun autoReg(@Query("cardNo") cardNo: String?): Call<AutoReg>

这里 @ContentType(DataType.XML) 指定了该接口返回的数据是 xml 的,不加这个注解 或者 加 @ContentType(DataType.JSON)  则是 JSON,至于 xml 解析,我们下篇再说。

full-stack-trip

Share
Published by
full-stack-trip

Recent Posts

Android 自定义 View 入门

说来惭愧,工作数年,连基本的自…

4 年 ago

mysql - 存储过程 从入门到放弃

最近有个报表的需求,于是乎用了…

4 年 ago

奶嘴战略 - 你不得不知道的扎心真相(一)

一句:英雄枯骨无人问,戏子家事…

4 年 ago

acme.sh 的简单使用

acme.sh 是纯 shel…

4 年 ago

wrk -更现代化的http压测工具

wrk 是一款更现代化的 ht…

4 年 ago

java 枚举类实现的单例与 spring boot 枚举类依赖注入

我们知道,在单例的诸多实现里,…

4 年 ago