- 一般服务端返回的数据格式都是这样的
{
"code":0,
"msg":"请求成功",
"data":{
"id":123456,
"name":"张三",
"age":18
}
}
- 那么你需要定义的JavaBean有两种方式
public class Login{
public int code;
public String msg;
public ServerModel data;
public class ServerModel{
public long id;
public String name;
public int age;
}
}
- 对于这种方式,我们在创建 JsonCallback 的时候,需要这么将
Login
作为一个泛型传递
OkGo.get(Urls.URL_METHOD)//
.tag(this)//
.execute(new JsonCallback<Login>(this) {
@Override
public void onSuccess(Login login, Call call, Response response) {
}
});
- 那么在
JsonCallback
中对应的解析代码如下,详细的原理就不说了,下面的注释很详细
@Override
public T convertSuccess(Response response) throws Exception {
//以下代码是通过泛型解析实际参数,泛型必须传
//com.lzy.demo.callback.DialogCallback<com.lzy.demo.model.Login> 得到类的泛型,包括了泛型参数
Type genType = getClass().getGenericSuperclass();
//从上述的类中取出真实的泛型参数,有些类可能有多个泛型,所以是数值
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
//我们的示例代码中,只有一个泛型,所以取出第一个,得到如下结果
//com.lzy.demo.model.Login
Type type = params[0];
//这里我们既然都已经拿到了泛型的真实类型,即对应的 class ,那么当然可以开始解析数据了,我们采用 Gson 解析
//以下代码是根据泛型解析数据,返回对象,返回的对象自动以参数的形式传递到 onSuccess 中,可以直接使用
JsonReader jsonReader = new JsonReader(response.body().charStream());
//有数据类型,表示有data
T data = Convert.fromJson(jsonReader, type);
response.close();
return data;
}
public class LzyResponse<T> {
public int code;
public String msg;
public T data;
}
public class ServerModel {
public long id;
public String name;
public int age;
}
- 提供的demo中按照第二种方式实现的,对于第二种方式,我们在创建 JsonCallback 的时候,需要这么将
LzyResponse<ServerModel>
作为一个泛型传递,相当于传递了两层,泛型中包含了又一个泛型
OkGo.get(Urls.URL_METHOD)//
.tag(this)//
.execute(new JsonCallback<LzyResponse<ServerModel>>(this) {
@Override
public void onSuccess(LzyResponse<ServerModel> responseData, Call call, Response response) {
}
});
- 那么在
JsonCallback
中对应的解析代码如下,详细的原理就不说了,下面的注释很详细
@Override
public T convertSuccess(Response response) throws Exception {
// 重要的事情说三遍,不同的业务,这里的代码逻辑都不一样,如果你不修改,那么基本不可用
// 重要的事情说三遍,不同的业务,这里的代码逻辑都不一样,如果你不修改,那么基本不可用
// 重要的事情说三遍,不同的业务,这里的代码逻辑都不一样,如果你不修改,那么基本不可用
//以下代码是通过泛型解析实际参数,泛型必须传
//这里为了方便理解,假如请求的代码按照上述注释文档中的请求来写,那么下面分别得到是
//com.lzy.demo.callback.DialogCallback<com.lzy.demo.model.LzyResponse<com.lzy.demo.model.ServerModel>> 得到类的泛型,包括了泛型参数
Type genType = getClass().getGenericSuperclass();
//从上述的类中取出真实的泛型参数,有些类可能有多个泛型,所以是数值
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
//我们的示例代码中,只有一个泛型,所以取出第一个,得到如下结果
//com.lzy.demo.model.LzyResponse<com.lzy.demo.model.ServerModel>
Type type = params[0];
// 这里这么写的原因是,我们需要保证上面我解析到的type泛型,仍然还具有一层参数化的泛型,也就是两层泛型
// 如果你不喜欢这么写,不喜欢传递两层泛型,那么以下两行代码不用写,并且javabean按照第一种方式定义就可以实现
if (!(type instanceof ParameterizedType)) throw new IllegalStateException("没有填写泛型参数");
//如果确实还有泛型,那么我们需要取出真实的泛型,得到如下结果
//class com.lzy.demo.model.LzyResponse
//此时,rawType的类型实际上是 class,但 Class 实现了 Type 接口,所以我们用 Type 接收没有问题
Type rawType = ((ParameterizedType) type).getRawType();
//这里我们既然都已经拿到了泛型的真实类型,即对应的 class ,那么当然可以开始解析数据了,我们采用 Gson 解析
//以下代码是根据泛型解析数据,返回对象,返回的对象自动以参数的形式传递到 onSuccess 中,可以直接使用
JsonReader jsonReader = new JsonReader(response.body().charStream());
if (rawType == Void.class) {
//无数据类型,表示没有data数据的情况(以 new DialogCallback<LzyResponse<Void>>(this) 以这种形式传递的泛型)
SimpleResponse baseWbgResponse = Convert.fromJson(jsonReader, SimpleResponse.class);
response.close();
//noinspection unchecked
return (T) baseWbgResponse.toLzyResponse();
} else if (rawType == LzyResponse.class) {
//有数据类型,表示有data
LzyResponse lzyResponse = Convert.fromJson(jsonReader, type);
response.close();
int code = lzyResponse.code;
//这里的0是以下意思
//一般来说服务器会和客户端约定一个数表示成功,其余的表示失败,这里根据实际情况修改
if (code == 0) {
//noinspection unchecked
return (T) lzyResponse;
} else if (code == 104) {
//比如:用户授权信息无效,在此实现相应的逻辑,弹出对话或者跳转到其他页面等,该抛出错误,会在onError中回调。
throw new IllegalStateException("用户授权信息无效");
} else if (code == 105) {
//比如:用户收取信息已过期,在此实现相应的逻辑,弹出对话或者跳转到其他页面等,该抛出错误,会在onError中回调。
throw new IllegalStateException("用户收取信息已过期");
} else if (code == 106) {
//比如:用户账户被禁用,在此实现相应的逻辑,弹出对话或者跳转到其他页面等,该抛出错误,会在onError中回调。
throw new IllegalStateException("用户账户被禁用");
} else if (code == 300) {
//比如:其他乱七八糟的等,在此实现相应的逻辑,弹出对话或者跳转到其他页面等,该抛出错误,会在onError中回调。
throw new IllegalStateException("其他乱七八糟的等");
} else {
throw new IllegalStateException("错误代码:" + code + ",错误信息:" + lzyResponse.msg);
}
} else {
response.close();
throw new IllegalStateException("基类错误无法解析!");
}
}
更详细的代码请自行看 demo ,有很详细的注释,JsonConvet 与 JsonCallback 一样,只是 JsonCallback 是在传统回调形式中用的,而 JsonConvert 是在 OkRx 中使用的,其余没有任何区别
分析上面两种写法,对于第一种,如果服务端返回了这么个数据
{
"code":300,
"msg":"用户名或密码错误",
}
那么对于第一种,很明显,这样的的数据应该要回调onError
的,但是我们在convertSuccess
中只是解析了数据,并不知道数据中的code
码300是表示错误数据的,我们仍然会解析数据并返回,这就导致了会回调onSuccess
,之后我们需要在onSuccess
中判断code
码,给予用户错误提示或者做成功跳转的逻辑。这样做的结果是,把无论正确的还是错误的数据,都交给了onSuccess
处理,在使用上不太友好。
所以我推荐的是第二种方式,这种方式不仅可以正确的解析数据,而且能在解析的过程中判断错误码,并根据不同的错误码抛出不同的异常(这里抛出异常并不会导致okgo挂掉,而是以异常的形式通知okgo回调onError
,并且将该异常以参数的形式传递到onError
),这样做后,在onSuccess
中处理的一定是成功的数据,在onError
中处理的一定是失败的数据,达到了友好的逻辑交互。
正是因为我推荐的是第二种写法,而第二种写法是依赖于业务中定义的数据结构的,不同的项目定义的数据结构都不一样,无法封装到库中,所以用demo的形式提供示例代码,根据需要自己修改。
如果有些服务器后台并没有统一数据格式,那么这个时候还是使用第一种方式吧。