利用Retrofit中Converter进行数据转换处理

retrofit中传入自定义的数据类型,比如Date、xxEntity等,但这些数据类型retrofit是不支持的,需要我们来提供处理的coverter

  1. @Query中传入Date参数,接口如下:
	/**
     * 获取 banner
     * 参数date,retrofite是无法解析的
     */
    @GET("banner/json")
    fun getBanner(@Query("date" ) date: Date): Call<BaseEntity<Any>>
  1. 提供自定义的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()
        }

    }

}
  1. 注册到Retrofit中
    private val retrofit: Retrofit = Retrofit.Builder().baseUrl(BaseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .addConverterFactory(DateConverterFactory.create())//注册Date处理Converter到Retrofit
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .client(httpClient)
            .build()
  1. @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);
    }
  }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章