例如一般网络响应都是这样封装,code msg data,很多时候只要使用 data,code 有错误就统一逻辑处理了。这时就需要一个 convertor 转换直接取出 data
编写 retrofit 的service 就方法返回值就不用都是 Call<HttpData<DataT>>
层层套娃了,变成了 Call<DataT>
, 使用 Kt 挂起函数直接变成 DataT
直接上代码:
HttpData
/**
* desc : 统一接口数据结构
*/
open class HttpData<T> {
/** 返回码 */
private val code: Int = 0
/** 提示语 */
private val message: String? = null
/** 数据 */
private val data: T? = null
fun getCode(): Int {
return code
}
fun getMessage(): String? {
return message
}
fun getData(): T? {
return data
}
/**
* 是否请求成功
*/
fun isRequestSucceed(): Boolean {
return code == 200
}
/**
* 是否 Token 失效
*/
fun isTokenFailure(): Boolean {
return code == 1001
}
}
CustomGsonConverterFactory.kt
class CustomGsonConverterFactory private constructor(private var gson: Gson) : Converter.Factory() {
companion object {
fun create(): CustomGsonConverterFactory {
return create(Gson())
}
fun create(gson: Gson): CustomGsonConverterFactory {
return CustomGsonConverterFactory(gson)
}
}
@EverythingIsNonNull
override fun responseBodyConverter(
type: Type,
annotations: Array<out Annotation>,
retrofit: Retrofit
): Converter<ResponseBody, *> {
val adapter = gson.getAdapter(TypeToken.get(type))
return CustomResponseBodyConverter(gson, adapter, TypeToken.get(type))
}
/**
* 自定义 GsonResponseBodyConverter, 转化 ResponseBody 中的 `data`为对象,
* 并对返回错误的情况进行异常处理
*/
private inner class CustomResponseBodyConverter<T> constructor(
private val gson: Gson,
private val adapter: TypeAdapter<T>,
private val token: TypeToken<*>
) :
Converter<ResponseBody, T?> {
@Throws(IOException::class)
override fun convert(value: ResponseBody): T? {
val base = gson.fromJson(value.charStream(), HttpData::class.java)
// 错误处理
if (!base.isRequestSucceed()) {
throw ApiException(base.getCode(), base.getMessage())
}
// 返回数据解析, use 结束后调用 values 的 close
return value.use { _ ->
val basic = checkBasicType(base)
if (basic != null) {
return basic as T
}
if (base.getData() == null) null else adapter.fromJson(gson.toJson(base.getData()))
}
}
/**
* 判断返回数据是不是基本数据类型(包含String)。如果是,则转化后返回。
*
* @param httpData 返回数据对象
* @return 转化后的对象,如果不是基本类型,则返回null
*/
private fun checkBasicType(httpData: HttpData<*>): Any? {
val typeName = token.rawType.simpleName
val data = httpData.getData().toString()
return when (typeName) {
"String" -> data
"Boolean" -> Boolean.parseBoolean(data)
"Integer" -> data.toInt()
else -> null
}
}
}
override fun requestBodyConverter(
type: Type,
parameterAnnotations: Array<out Annotation>,
methodAnnotations: Array<out Annotation>,
retrofit: Retrofit
): Converter<*, RequestBody>? {
val adapter = gson.getAdapter(TypeToken.get(type))
return CustomRequestBodyConverter(gson, adapter)
}
/**
* 与 GsonConverterFactory 一致
*/
private inner class CustomRequestBodyConverter<T> constructor(gson: Gson, adapter: TypeAdapter<T>) :
Converter<T, RequestBody> {
private val MEDIA_TYPE: MediaType = "application/json; charset=UTF-8".toMediaType()
private val UTF_8 = StandardCharsets.UTF_8
private val gson: Gson
private val adapter: TypeAdapter<T>
init {
this.gson = gson
this.adapter = adapter
}
override fun convert(value: T): RequestBody {
val buffer = Buffer()
val writer = OutputStreamWriter(buffer.outputStream(), UTF_8)
val jsonWriter = gson.newJsonWriter(writer)
adapter.write(jsonWriter, value)
jsonWriter.close()
return buffer.readByteString().toRequestBody(MEDIA_TYPE)
}
}
}