您的位置:首页 > 移动开发 > Android开发

android retrofit 实战自定义converter,解决相同接口返回不同数据的问题

2017-01-10 23:51 561 查看
square的retrofit是目前比较火的网络框架,我目前也在用

今天项目上遇到一个问题,就是请求同一个接口,可能返回不同的json格式

例如,访问一个登录接口,成功的时候,返回的是

{

    "code": 0,

    "message": "登录成功",

    "data": {

        "username": "xxx",

        "userId": "xxx"

    }

}

我们首先定义一个basebean

public class Base {

public String message;
public int code;

}


然后定义一个loginbean去接收数据

public class LoginBean extends Base{

public LoginContent data;

public class LoginContent {
public String username;
public String userId;
}

}


访问失败的时候,服务器自动转发了地址,返回服务器维护的提示

{

    "code": 1,

    "message": "服务器维护中",

    "data": {

        "title": "xxx",

        "content": "xxx"

    }

}

而我们通常用retrofit写接口,都是通过下面这种方式

@FormUrlEncoded
@POST("user/login")
Observable<LoginBean> login(@Field("userInfo.mobile") String mobile, @Field("userInfo.passWord") String pwd);
这里把泛型写死成了loginbean,

而我们通常在初始化时候,都会添加如下代码

new Retrofit.Builder()
.baseUrl(Constants.SERVER_URL)
.addConverterFactory(GsonConverterFactory.create())
//添加回调库,采用RxJava
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(genericClient())
.build();

这里的
GsonConverterFactory.create()


返回的是一个converterFactory,就是用于我们的json解析的

如果我们用的converter是默认的GsonConverter的话,retrofit就会按照
loginbean的格式解析,当访问异常的时候,json返回的格式变了,json自然就解析失败了。
于是我想过很多方法,例如把泛型换成base,到回调的时候再继续解析

但是想想,以后所有的接口都要这么写,岂不是要吐血?

那么,我们如何通过不修改泛型,又可以实现数据的正常解析呢?

我采用的解决办法是自定义converter

首先在base中扩展一个字段

public class Base {

public String message;
public int code;
public Notify notify;
}


不多说,Notify的代码就不贴了,看converter

public class MyGsonResponseBodyConverter<T extends Base> implements Converter<ResponseBody, T> {

private final Gson gson;
private final Type type;

public MyGsonResponseBodyConverter(Gson gson, Type type) {
this.gson = gson;
this.type = type;
}

@Override
public T convert(ResponseBody value) throws IOException {
String json = value.string();
JsonObject jsonObject = new JsonParser().parse(json).getAsJsonObject();
// 解析code
JsonPrimitive jsonPrimitive = jsonObject.getAsJsonPrimitive("code");
int code = 0;
if (jsonPrimitive != null) {
code = jsonPrimitive.getAsInt();
}
// 解析message
JsonElement jsonElement = jsonObject.get("message");
String message = null;
if (jsonElement != null) {
massage = jsonElement.getAsString();
}

T t = null;
try {
// 通过反射获取泛型的实例对象
Class<T> clazz = (Class<T>) type;
t = clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}

if (code == 1 ) {
// 按停服公告的格式解析,封装到notify字段中
t.notify = gson.fromJson(jsonObject.getAsJsonObject("data"), Notify.class);
} else {
// 按标准格式解析
return gson.fromJson(json, type);
}

return t;
}
}


上面代码可以看到,我们先去解析code,然后判断不同的code去做不同的解析,

当返回的数据是停服公告时,就将解析到的data,封装到notify里面去,就可以避免json解析的异常

也可以正常返回数据

接下来自定义一个converterFactory

public class MyGsonConverterFactory extends Converter.Factory {

/**
* Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and
* decoding from JSON (when no charset is specified by a header) will use UTF-8.
*/
public static MyGsonConverterFactory create() {
return create(new Gson());
}

/**
* Create an instance using {@code gson} for conversion. Encoding to JSON and
* decoding from JSON (when no charset is specified by a header) will use UTF-8.
*/
public static MyGsonConverterFactory create(Gson gson) {
return new MyGsonConverterFactory(gson);
}

private final Gson gson;

private MyGsonConverterFactory(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
this.gson = gson;
}

@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
return new MyGsonResponseBodyConverter<>(gson, type);
}

@Override
public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations,
Annotation[] methodAnnotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new MyGsonRequestBodyConverter<>(gson, adapter);
}
}


其实就是把源码复制下来改了改。最后,把converter改成自己的converter

new Retrofit.Builder()
.baseUrl(Constants.SERVER_URL)
.addConverterFactory(MyGsonConverterFactory.create())
//添加回调库,采用RxJava
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(genericClient())
.build();


不过这么写也有局限性,就是当使用这个converter时,所有的bean都要继承base类,

而且每当服务器改变一种结构,我们都必须修改converter

这样会相当麻烦,暂时没有想到更好的解决办法,如果有大神有更好的办法欢迎指教

本人qq184497436
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android retrofit 网络 json
相关文章推荐