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 解析,我们下篇再说。