retrofit動態設置json或xml或其他轉換工廠

retrofit轉換工廠介紹

retrofit是個強大的工具,而retrofit converter可以把請求的結果轉爲可供我們直接使用的java bean對象。如果不使用轉換工廠retrofit則請求方法回只能爲ResponseBody對象。
官方爲我們提供了一些默認的轉換工廠:https://github.com/square/retrofit/tree/master/retrofit-converters

public interface GitHubService {
  @GET("users/{user}")
  Call<User> getUserInfo(@Path("user") String user);
}

要使用工廠就要在retrofit實例設置轉換工廠:

Retrofit retrofit = new Retrofit.Builder()
    .addConverterFactory(GsonConverterFactory.create())
    .build();

這裏設置了一個GsonConverterFactory,它可以把http請求響應json數據轉爲java bean;這裏json數據被反序列化爲User對象了;但是這個retrofit對象就只能處理gson數據了;

一般服務器接口所返回的數據結構都是統一規範的,比如返回數據結構爲JSON;那如果有特殊情況怎麼辦?比如服務中有個接口返回xml數據,上面的retrofit實例就不能用了,只能從新創建了;

可以混用的轉換工廠CompositeConverterFactory

聲明工廠CompositeConverterFactory

自定義一個可以混用的轉換工廠,它自己並不處理數據,給它設置默認工廠來處理數據,比如GsonConverterFactory就處理json數據,設置SimpleXmlConverterFactory就處理xml數據;並且還可以在請求方法上設置註解來動態設置轉換工廠;

CompositeConverterFactory.java

public class CompositeConverterFactory extends Converter.Factory {

    private Converter.Factory mFactory;

    public static CompositeConverterFactory create(Converter.Factory factory) {
        if (factory == null) {
            throw new NullPointerException("parameter is null");
        } else {
            return new CompositeConverterFactory(factory);
        }
    }

    private CompositeConverterFactory(Converter.Factory factory) {
        this.mFactory = factory;
    }

    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
        Class<?> factoryClass = null;
        for (Annotation annotation : annotations) {
            if (annotation instanceof ResponseConverter) {
                factoryClass = ((ResponseConverter) annotation).value();
                break;
            }
        }

        Converter.Factory factory = null;
        if (factoryClass != null) {
            try {
                Method createMethod = factoryClass.getMethod("create");
                factory = (Converter.Factory) createMethod.invoke(null);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }

        if (factory == null && mFactory != null) {
            factory = mFactory;
        }

        if (factory != null)
            return factory.responseBodyConverter(type, annotations, retrofit);

        return super.responseBodyConverter(type, annotations, retrofit);
    }

    @Override
    public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
        Class<?> factoryClass = null;
        for (Annotation paramAnno : methodAnnotations) {
            if (paramAnno instanceof RequestConverter) {
                factoryClass = ((RequestConverter) paramAnno).value();
                break;
            }
        }

        Converter.Factory factory = null;
        if (factoryClass != null) {
            try {
                Method createMethod = factoryClass.getMethod("create");
                factory = (Converter.Factory) createMethod.invoke(null);
                return factory.requestBodyConverter(type, parameterAnnotations, methodAnnotations, retrofit);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }

        if (factory == null && mFactory != null) {
            factory = mFactory;
        }

        if (factory != null)
            return factory.requestBodyConverter(type, parameterAnnotations, methodAnnotations, retrofit);

        return super.requestBodyConverter(type, parameterAnnotations, methodAnnotations, retrofit);
    }
}

聲明註解@RequestConverter

@RequestConverter

@Documented
@Target({METHOD})
@Retention(RUNTIME)
public @interface RequestConverter {
    Class<? extends Converter.Factory> value();
}

聲明註解@ResponseConverter

@ResponseConverter

@Documented
@Target({METHOD})
@Retention(RUNTIME)
public @interface ResponseConverter {
    Class<? extends Converter.Factory> value();
}

CompositeConverterFactory的使用

使用自定義轉換工廠:

Retrofit retrofit = new Retrofit.Builder()
    .addConverterFactory(CompositeConverterFactory.create(GsonConverterFactory.create()))
    .build();

這裏默認設置GsonConverterFactory,默認處理json數據結構的數據。CompositeConverterFactory轉換什麼數據由傳入的默認工廠決定。

@RequestConverter @ResponseConverter 的使用:

CompositeConverterFactory.create(factory)傳入參數爲默認工廠;

case1 接口返回的json數據轉爲對象

public interface GitHubService {
    @ResponseConverter(GsonConverterFactory.class) 
    @GET("users/{user}")
    Call<User> getUserInfo(@Path("user") String user);
  }

case2 獲取接口返回的原始數據(字符串) json 或 xml 或 其他

  @ResponseConverter(ScalarsConverterFactory.class) 
  @GET("users/{user}")
  Call<String> getUserInfo2(@Path("user") String user);

case3 把javabean轉爲json字符串以post方式上傳到服務器端

  @RequestConverter(GsonConverterFactory.class) 
  @POST("/uploaddata")
  Call<String> upload(@Body User user);

是不是很簡單?It is easy!!!

在gradle中添加依賴即可使用

repositories {
    jcenter()
}

dependencies {
    implementation 'com.github.woodyhi.retrofit:composite-converter:0.1.3'
}

PS:源碼 https://github.com/woodyhi/retrofit-converter 其中有test代碼來演示。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章