项目使用了Retrofit2+rxjava2+gson 处理网络请求的数据处理,这里主要介绍gson部分。
retrofit2有专门的converter只要依赖以后就可以使用gson啦。
compile 'com.squareup.retrofit2:retrofit:2.1.0' compile 'com.squareup.retrofit2:converter-gson:2.1.0'
然后需要在新建retrofit类时addConverterFactory,如果不需要使用特定的Gson,比如添加自己的TypeAdpter特殊处理的话,可以不传gson对象,factory会自己新建一个。
@Singleton @Provides Retrofit provideRetrofit(OkHttpClient client, Gson gson){ return new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create(gson)) .addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io())) .client(client) .build(); }
这样gson就初步配置好啦。
public class Bean<T> { private String msg; @SerializedName(value = "status", alternate = {"Status"}) private int resultCode; @SerializedName("data") private T result; }这个bean对应的是json结构是{"data":[],"msg":"","status":0}
@FormUrlEncoded @POST(value = "login.html") Observable>> login(@Field("token") String token, @Field("username") String user, @Field("password") String passWord);
Result形式的对象了,可以方便的从中获得数据。
Bean<T> b = result.response().body();
在具体业务处理的过程中,会遇到同样的字段,在不同情况下服务器返回不同类型的情况。
JsonDeserializer
我们这里主要处理服务器端的返回数据,所以选择使用JsonDeserializer
public class BeanTypeDeserializer implements JsonDeserializer{ @Override public Bean deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject obj = json.getAsJsonObject();return new Bean<>(obj.get( "msg" ).getAsString() , obj.get( "status" ).getAsInt() ,new Object()) ; }} 虽然,bean带有泛型,但是在编译期间泛型便会被擦除,这里没必要写成
JsonElement是json数据。
Type就是处理数据得类型,这里应该是Bean
JsonDeserializationContext 是反序列化的上下文。
上面做的是一个简单处理,只是忽略了返回中的data数据,传了一个Object。这显然是无法满足需要的。
因为,data中的数据是多种多样的类,我们不可能自己一一处理。
这里就需要用到JsonDeserializationContext ,将data中的json重新交给Gson去做进一步处理,这是一个接口对象只有一个方法:
public <T> T deserialize(JsonElement json, Type typeOfT) throws JsonParseException;我们需要传入jsonElement数据,Type(我们希望转换得到的类,也就是这个方法的返回T的类型)
jsonElement我们可以通过obj.get()得到。
而Type,在这个情况下其实是不确定的,一开始我考虑传入T,通过Gson提供的TypeToken获取。
public class BeanTypeDeserializer<T> implements JsonDeserializer可惜这并不能正常工作,因为T在编译时已经被擦除了,而我们在new BeanTypeDeserializer时是不可能传入T的具体类的,在运行中这个T会是各种类型。T>> { @Override public Bean deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject obj = json.getAsJsonObject(); context.deserialize(obj.get("data"), new TypeToken<T>() {}.getType()); }
这里我们就要使用传入的typeOfT,正确的解决方式是:
context.deserialize(obj.get("data"), ((ParameterizedType) typeOfT).getActualTypeArguments()[0])
最终的解决方式:
public class BeanTypeDeserializer<T> implements JsonDeserializer我这里,在status不为0时,代表了服务器不是正常返回,所以我不处理data的数据,这样就可以避免出错。T>> { @Override public Bean deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject obj = json.getAsJsonObject(); int status = obj.get("status").getAsInt(); if(status==0){ return new Bean<>(obj.get("msg").getAsString(),status, context.deserialize(obj.get("data"), ((ParameterizedType) typeOfT).getActualTypeArguments()[0])); }else { return new Bean<>(obj.get("msg").getAsString(),status,new Object()); } } }
@Provides Gson provideGson(){ return new GsonBuilder().registerTypeAdapter(Bean.class, new BeanTypeDeserializer()).create(); }调用registerTypeAdapter方法
public GsonBuilder registerTypeAdapter(Type type, Object typeAdapter)Type就是注册对那个类做处理,后面就是我们的处理类。