retrofit中傳入自定義的資料類型,比如Date、xxEntity等,但這些資料類型retrofit是不支援的,需要我們來提供處理的coverter
- @Query中傳入Date參數,接口如下:
/**
* 擷取 banner
* 參數date,retrofite是無法解析的
*/
@GET("banner/json")
fun getBanner(@Query("date" ) date: Date): Call<BaseEntity<Any>>
- 提供自定義的Coverter和ConverterFactory
/**
* 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()
}
}
}
- 注冊到Retrofit中
private val retrofit: Retrofit = Retrofit.Builder().baseUrl(BaseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addConverterFactory(DateConverterFactory.create())//注冊Date處理Converter到Retrofit
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(httpClient)
.build()
-
@POST RequestBody資料轉換
原來接口:
/**
* 登陸
*/
@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<SimpleResponse>}
* 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<String, ? extends Runnable>} 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);
}
}
}