Android培训
美国上市Android培训机构

400-111-8989

热门课程

Android中的Rxjava、Retrofit返回json数据解析异常处理

  • 发布:莫比乌丝环
  • 来源:安卓巴士Android开发者门户
  • 时间:2018-10-30 18:03

今天我们android培训分享给大家的是Rxjava、Retrofit返回json数据解析异常处理的相关方法,每个App都避免不了要进行网络请求,从最开始的用谷歌封装的volley到再到android-async-http再到OKHttpUtils再到现在的Retrofit和RxJava,从我自己用后的体验来看,用了retrofit和RxJava真的回不去了,不多少了,我们来看正文吧:

1、Rxjava和Retrofit依赖导入:

compile 'io.reactivex:rxandroid:1.2.0' //Rxjava专门针对anroid封装的RxAndroid

compile 'io.reactivex:rxjava:1.1.5'

compile 'com.squareup.retrofit2:retrofit:2.0.2' //retrofit

compile 'com.squareup.retrofit2:converter-gson:2.0.2' //gson converter

compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2' //Retrofit专门为Rxjava封装的适配器

compile 'com.google.code.gson:gson:2.6.2' //Gson

compile 'com.squareup.okhttp3:logging-interceptor:3.1.2' //打印网络请求的log日志

2、网络请求基类的配置

建立一个工厂类

public class ServiceFactory {

private final Gson mGsonDateFormat;

public ServiceFactory(){

mGsonDateFormat = new GsonBuilder()

.setDateFormat("yyyy-MM-dd hh:mm:ss")

.create();

}

private static class SingletonHolder{

private static final ServiceFactory INSTANCE = new ServiceFactory();

}

public static ServiceFactory getInstance(){

return SingletonHolder.INSTANCE;

}

public <S> S createService(Class<S> serviceClass){

Retrofit retrofit = new Retrofit.Builder()

.baseUrl(Constant.BASE_URL) //Retrofit2 base url 必须是这种格式的:http://xxx.xxx/

.client(getOkHttpClient())

--------------------------添加Gson工厂变换器也就是不用管数据解析-----------------------------------

.addConverterFactory(GsonConverterFactory.create())

.addCallAdapterFactory(RxJavaCallAdapterFactory.create())

.build();

return retrofit.create(serviceClass);

}

HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {

@Override

public void log(String message) {

//打印retrofit日志

Log.i("RetrofitLog","retrofitBack ======================= "+message);

}

});

private static final long DEFAULT_TIMEOUT = 10;

private OkHttpClient getOkHttpClient(){

loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

//定制OkHttp

OkHttpClient.Builder builder = new OkHttpClient.Builder();

builder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);

builder.writeTimeout(DEFAULT_TIMEOUT,TimeUnit.SECONDS);

builder.addInterceptor(loggingInterceptor);

//设置缓存

File httpCacheDirectory = new File(SDCardUtils.getRootDirectoryPath(),"这里是你的网络缓存存放的地址");

builder.cache(new Cache(httpCacheDirectory,10*1024*1024));

return builder.build();

}

}

好了,下一步:我们要建一个网络请求的基类,一般网络请求返回的数据最外层的根式就是 code msg result,可变的就是result,所以我们把result的类型定义为一个泛型的,

public class HttpResult<T> extends BaseEntity {

public int code;

private boolean isSuccess;

private T result;

private String msg;

public void setMsg(String msg) {

this.msg = msg;

}

public T getResult() {

return result;

}

public void setResult(T result) {

this.result = result;

}

public boolean isSuccess() {

return code == 200;

}

public int getCode() {

return code;

}

}

既然我们的网络请求是rxjava配合retrofit 下面就定义我们的网络请求订阅subscriber

public abstract class HttpResultSubscriber<T> extends Subscriber<HttpResult<T>> {

@Override

public void onNext(HttpResult<T> t) {

if (t.isSuccess()) {

onSuccess(t.getResult());

} else {

_onError(t.getMsg().getCode());

}

}

@Override

public void onCompleted() {

}

@Override

public void onError(Throwable e) {

e.printStackTrace();

//在这里做全局的错误处理

if (e instanceof ConnectException ||

e instanceof SocketTimeoutException ||

e instanceof TimeoutException) {

//网络错误

_onError(-9999);

}

}

public abstract void onSuccess(T t);

public abstract void _onError(int status);

}

OK我们的网络请求基类已经完成啦!下面开始我们的网络请求

首先我们定义一个接口(以登录为例):

public interface LoginService {

//这个例子是post为例,如果想要了解其他的网络请求,请点击文章开始出的retrofit链接

@FormUrlEncoded

@POST(Constant.LOGIN_URL) 这里是你的登录url

//可以看到我们的登录返回的是一个Observable,它里面包含的使我们的网络请求返回的实体基类,

//而我们实体基类的result现在就是UserInfoEntity

Observable<HttpResult<UserInfoEntity>> login(@Field("mobile") String phone,

@Field("password") String pwd);

}

现在开始我们的网络请求啦

public void login(String phone, String pwd) {

ServiceFactory.getInstance()

.createService(LoginService.class)

.login(phone,pwd)

.compose(TransformUtils.<HttpResult<UserInfoEntity>>defaultSchedulers())

.subscribe(new HttpResultSubscriber<UserInfoEntity>() {

@Override

public void onSuccess(UserInfoEntity userInfoEntity) {

//这是网络请求陈宫的回调

}

@Override

public void _onError(int status) {

//这是失败的回调 根据status做具体的操作

}

});

}

你以为这样就行了 , 这样子确实没毛病,确实已经妥妥的了。可是,可是,事与愿违啊!!!

3、具体解决办法

一般情况这是我们的返回json格式:

{

"code":200,

"msg":"成功",

"result":{}

}

我们刚才定义登录接口的时候 返回的实体基类例传入的是UserInfoEntity 这确实是没问题的 可是你们加入登录失败的时候返回的json数据格式是这样的怎么办?

{

"code":300,

"msg":"成功",

"result":[]

}

失败的时候返回的实体又是一个数组,这样子就会抱一个json解析异常拿不多失败的状态码和提示信息

OK其实我们的网络请求已经完成90%了,剩下的就是不重要的失败的时候回调了。

方法一:

我们可以让后台返回的json数据中的result永远是个数组。

{

"code":300,

"msg":"成功",

"result":[]

}

方法二:

首先给大家看一个图片

android中的Rxjava、Retrofit返回json数据解析异常处理

这就是我们要下手的地方

上面我们添加的工厂变换器是导入的依赖 compile 'com.squareup.retrofit2:converter-gson:2.0.2' 这个提供的

那可能有人要问了,那我们不用这个用哪个啊,不着急,不着急。还好retrofit是支持自定义的ConverterFactory的

下面我们就开始我们的自定义征程吧。

1、自定义Gson响应体变换器

public class GsonResponseBodyConverter<T> implements Converter<ResponseBody,T>{

private final Gson gson;

private final Type type;

public GsonResponseBodyConverter(Gson gson,Type type){

this.gson = gson;

this.type = type;

}

@Override

public T convert(ResponseBody value) throws IOException {

String response = value.string();

//先将返回的json数据解析到Response中,如果code==200,则解析到我们的实体基类中,否则抛异常

Response httpResult = gson.fromJson(response, Response.class);

if (httpResult.getCode()==200){

//200的时候就直接解析,不可能出现解析异常。因为我们实体基类中传入的泛型,就是数据成功时候的格式

return gson.fromJson(response,type);

}else {

ErrorResponse errorResponse = gson.fromJson(response,ErrorResponse.class);

//抛一个自定义ResultException 传入失败时候的状态码,和信息

throw new ResultException(errorResponse.getCode(),errorResponse.getMsg());

}

}

}

2、自定义一个响应变换工厂 继承自 retrofit的 converter.Factory

public class ResponseConverterFactory extends Converter.Factory {

public static ResponseConverterFactory create() {

return create(new Gson());

}

public static ResponseConverterFactory create(Gson gson) {

return new ResponseConverterFactory(gson);

}

private final Gson gson;

private ResponseConverterFactory(Gson gson) {

if (gson == null) throw new NullPointerException("gson == null");

this.gson = gson;

}

@Override

public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {

//返回我们自定义的Gson响应体变换器

return new GsonResponseBodyConverter<>(gson, type);

}

@Override

public Converter<?, RequestBody> requestBodyConverter(Type type,

Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {

//返回我们自定义的Gson响应体变换器

return new GsonResponseBodyConverter<>(gson,type);

}

}

然后将上面的GsonConverterFactory.create() 替换成我们自定义的ResponseConverterFactory.create()。

public <S> S createService(Class<S> serviceClass){

Retrofit retrofit = new Retrofit.Builder()

.baseUrl(Constant.BASE_URL)

.client(getOkHttpClient())

//.addConverterFactory(GsonConverterFactory.create())

//然后将上面的GsonConverterFactory.create()替换成我们自定义的ResponseConverterFactory.create()

.addConverterFactory(ResponseConverterFactory.create())

.addCallAdapterFactory(RxJavaCallAdapterFactory.create())

.build();

return retrofit.create(serviceClass);

}

最后:

在我们的自定义的Rxjava订阅者 subscriber中的onError()中加入我们刚才定义的ResultException。

@Override

public void onError(Throwable e) {

e.printStackTrace();

//在这里做全局的错误处理

if (e instanceof ConnectException ||

e instanceof SocketTimeoutException ||

e instanceof TimeoutException) {

//网络错误

_onError(-9999);

} else if (e instanceof ResultException) {

//自定义的ResultException

//由于返回200,300返回格式不统一的问题,自定义GsonResponseBodyConverter凡是300的直接抛异常

_onError(((ResultException) e).getErrCode());

System.out.println("---------errorCode------->"+((ResultException) e).getErrCode());

}

}

这次是真的完成了我们的json数据解析异常的处理,其实我们的解决办法是解析了两次,第一次解析的时候我们的Response中只有只是解析了最外层的 code 和 msg ,result中的是没有解析的。response中的code==200,直接将数据解析到我们的实体基类中。如果code!=200时,直接抛自定义的异常,直接会回调到subscriber中的onError()中。虽然进行了两次解析,但是第一次只是解析了code,和msg 对于效率的影响其实并不大,在功能实现的基础上一点点效率的影响(而且这个影响是微乎其微的-.-)其实无伤大雅的。

感谢您的阅读,android中的Rxjava、Retrofit返回json数据解析异常处理,你学会了吗?更多android知识,尽在达内android培训,敬请关注!

免责声明:内容和图片源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

预约申请免费试听课

上一篇:Android中webview控件的相关使用详解
下一篇:达内Android培训分享:Android组件化之通信机制

Android中webview控件的相关使用详解

Android培训分享:Android中自定义进度加载工具类的使用

Android工程师分享Android应用架构,通俗易懂!

达内Android培训分享:Android组件化之通信机制

选择城市和中心
贵州省

广西省

海南省