利用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);
    }
  }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章