retrofit中传入自定义的数据类型,比如Date、xxEntity等,但这些数据类型retrofit是不支持的,需要我们来提供处理的coverter
/**
* 获取 banner
* 参数date,retrofite是无法解析的
*/
@GET("banner/json")
fun getBanner(@Query("date" ) date: Date): Call<BaseEntity<Any>>
/**
* Created by mayi on 2020-05-25.
*
*/
class DateConverter :Converter<Date,String> {
override fun convert(value: Date): String? {//将Date简单转换处理成String,给到okhttp
return SimpleDateFormat("yyyyMMdd_hhmmss").format(value)
}
}
/**
* Created by mayi on 2020-05-25.
*/
class DateConverterFactory :Converter.Factory() {
override fun stringConverter(type: Type, annotations: Array<Annotation>, retrofit: Retrofit): Converter<*, String>? {
//判断type是否Date数据类型,关键的一步
if (type == Date::class.java){
return DateConverter()
}
return super.stringConverter(type, annotations, retrofit)
}
companion object{
fun create(): Converter.Factory {
return DateConverterFactory()
}
}
}
private val retrofit: Retrofit = Retrofit.Builder().baseUrl(BaseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addConverterFactory(DateConverterFactory.create())//注册Date处理Converter到Retrofit
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(httpClient)
.build()
/**
* 登陆
*/
@FormUrlEncoded
@POST("user/login")
fun toLogin(@Field("username") username:String
,@Field("password") password:String):Call<BaseEntity<Any>>
改造后:
/**
* 登陆
*/
@POST("user/login")
fun toLogin4(@Body params: PkLinkMap):Call<BaseEntity<Any>>
PkLinkMap实体:
/**
* Created by mayi on 2020-05-30.
*/
class PkLinkMap :LinkedHashMap<String,String>()
提供Converter和ConverterFactory
/**
* Created by mayi on 2020-05-30.
*/
class PkLinkMapConverter : Converter<PkLinkMap, RequestBody> {
private val MEDIA_TYPE: MediaType = "application/json; charset=UTF-8".toMediaType()
override fun convert(value: PkLinkMap): RequestBody? {
value["other_params"] = "this is other params"
return RequestBody.create(MEDIA_TYPE, value.toJson())
}
}
/**
* Created by mayi on 2020-05-30.
*/
class PkLinkMapConverterFactory : Converter.Factory() {
override fun requestBodyConverter(type: Type,
parameterAnnotations: Array<Annotation>,
methodAnnotations: Array<Annotation>,
retrofit: Retrofit): Converter<*, RequestBody>? {
//判断类型
if (type== PkLinkMap::class.java){
return PkLinkMapConverter()
}
return super.requestBodyConverter(type, parameterAnnotations, methodAnnotations, retrofit)
}
companion object{
fun create(): Converter.Factory {
return PkLinkMapConverterFactory()
}
}
}
原理:Retrofit的参数处理是通过Converter进行处理的,其中Converter是一个接口,想处理特殊数据类型,自己实现并提供对应的ConcerterFactory就可以了。
Converter接口如下:
public interface Converter<F, T> {
@Nullable T convert(F value) throws IOException;
/** Creates {@link Converter} instances based on a type and target usage. */
abstract class Factory {
/**
* Returns a {@link Converter} for converting an HTTP response body to {@code type}, or null if
* {@code type} cannot be handled by this factory. This is used to create converters for
* response types such as {@code SimpleResponse} from a {@code Call}
* declaration.
*/
public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type,
Annotation[] annotations, Retrofit retrofit) {
return null;
}
/**
* Returns a {@link Converter} for converting {@code type} to an HTTP request body, or null if
* {@code type} cannot be handled by this factory. This is used to create converters for types
* specified by {@link Body @Body}, {@link Part @Part}, and {@link PartMap @PartMap}
* values.
*/
public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return null;
}
/**
* Returns a {@link Converter} for converting {@code type} to a {@link String}, or null if
* {@code type} cannot be handled by this factory. This is used to create converters for types
* specified by {@link Field @Field}, {@link FieldMap @FieldMap} values,
* {@link Header @Header}, {@link HeaderMap @HeaderMap}, {@link Path @Path},
* {@link Query @Query}, and {@link QueryMap @QueryMap} values.
*/
public @Nullable Converter<?, String> stringConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
/**
* Extract the upper bound of the generic parameter at {@code index} from {@code type}. For
* example, index 1 of {@code Map} returns {@code Runnable}.
*/
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
/**
* Extract the raw class type from {@code type}. For example, the type representing
* {@code List extends Runnable>} returns {@code List.class}.
*/
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}