Rxjava、Retrofit返回json数据解析异常处理
每個App都避免不了要進行網(wǎng)絡(luò)請求,從最開始的用谷歌封裝的volley到再到android-async-http再到OKHttpUtils再到現(xiàn)在的Retrofit和RxJava,從我自己用后的體驗來看,用了retrofit和RxJava真的回不去了,回不去了,不去了,去了,了…(哈哈,本來還想分析下這四個的區(qū)別,網(wǎng)上這樣的文章很多,我就沒必要多添亂了-.-)。不多逼逼,下面開始正文。
1、Rxjava和Retrofit依賴導(dǎo)入:
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' //打印網(wǎng)絡(luò)請求的log日志2、網(wǎng)絡(luò)請求基類的配置
建立一個工廠類
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工廠變換器也就是不用管數(shù)據(jù)解析-----------------------------------.addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()).build();return retrofit.create(serviceClass);}HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {@Overridepublic 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);//定制OkHttpOkHttpClient.Builder builder = new OkHttpClient.Builder();builder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);builder.writeTimeout(DEFAULT_TIMEOUT,TimeUnit.SECONDS);builder.addInterceptor(loggingInterceptor);//設(shè)置緩存File httpCacheDirectory = new File(SDCardUtils.getRootDirectoryPath(),"這里是你的網(wǎng)絡(luò)緩存存放的地址");builder.cache(new Cache(httpCacheDirectory,10*1024*1024));return builder.build();}}好了 下一步 我們要建一個網(wǎng)絡(luò)請求的基類,一般網(wǎng)絡(luò)請求返回的數(shù)據(jù)最外層的根式就是 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;} }既然我們的網(wǎng)絡(luò)請求是rxjava配合retrofit 下面就定義我們的網(wǎng)絡(luò)請求訂閱subscriber
public abstract class HttpResultSubscriber<T> extends Subscriber<HttpResult<T>> {@Overridepublic void onNext(HttpResult<T> t) {if (t.isSuccess()) {onSuccess(t.getResult());} else {_onError(t.getMsg().getCode());}}@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable e) {e.printStackTrace();//在這里做全局的錯誤處理if (e instanceof ConnectException ||e instanceof SocketTimeoutException ||e instanceof TimeoutException) {//網(wǎng)絡(luò)錯誤_onError(-9999);}}public abstract void onSuccess(T t);public abstract void _onError(int status); }OK我們的網(wǎng)絡(luò)請求基類已經(jīng)完成啦!下面開始我們的網(wǎng)絡(luò)請求
首先我們定義一個接口(以登錄為例):
public interface LoginService {//這個例子是post為例,如果想要了解其他的網(wǎng)絡(luò)請求,請點擊文章開始出的retrofit鏈接@FormUrlEncoded@POST(Constant.LOGIN_URL) 這里是你的登錄url//可以看到我們的登錄返回的是一個Observable,它里面包含的使我們的網(wǎng)絡(luò)請求返回的實體基類,//而我們實體基類的result現(xiàn)在就是UserInfoEntityObservable<HttpResult<UserInfoEntity>> login(@Field("mobile") String phone,@Field("password") String pwd); }現(xiàn)在開始我們的網(wǎng)絡(luò)請求啦
public void login(String phone, String pwd) {ServiceFactory.getInstance().createService(LoginService.class).login(phone,pwd).compose(TransformUtils.<HttpResult<UserInfoEntity>>defaultSchedulers()).subscribe(new HttpResultSubscriber<UserInfoEntity>() {@Overridepublic void onSuccess(UserInfoEntity userInfoEntity) {//這是網(wǎng)絡(luò)請求陳宮的回調(diào)}@Overridepublic void _onError(int status) {//這是失敗的回調(diào) 根據(jù)status做具體的操作}}); }你以為這樣就行了 , 這樣子確實沒毛病,確實已經(jīng)妥妥的了。可是,可是,事與愿違啊!!!
3、具體解決辦法
一般情況這是我們的返回json格式:
{"code":200,"msg":"成功","result":{} }我們剛才定義登錄接口的時候 返回的實體基類例傳入的是UserInfoEntity 這確實是沒問題的 可是你們加入登錄失敗的時候返回的json數(shù)據(jù)格式是這樣的怎么辦?
{"code":300,"msg":"成功","result":[] }失敗的時候返回的實體又是一個數(shù)組,這樣子就會抱一個json解析異常拿不多失敗的狀態(tài)碼和提示信息
OK其實我們的網(wǎng)絡(luò)請求已經(jīng)完成90%了,剩下的就是不重要的失敗的時候回調(diào)了。
方法一:(這是在后臺兄弟好說話,而且不打人的情況下…當然這種好人,還是有的,不過這不是我們今天要講的重點)
我們可以讓后臺返回的json數(shù)據(jù)中的result永遠是個數(shù)組。
{"code":300,"msg":"成功","result":[] }方法二:
首先給大家看一個圖片
這就是我們要下手的地方
上面我們添加的工廠變換器是導(dǎo)入的依賴 compile 'com.squareup.retrofit2:converter-gson:2.0.2' 這個提供的
那可能有人要問了,那我們不用這個用哪個啊,不著急,不著急。還好retrofit是支持自定義的ConverterFactory的
下面我們就開始我們的自定義征程吧。
1、自定義Gson響應(yīng)體變換器
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;}@Overridepublic T convert(ResponseBody value) throws IOException {String response = value.string();//先將返回的json數(shù)據(jù)解析到Response中,如果code==200,則解析到我們的實體基類中,否則拋異常Response httpResult = gson.fromJson(response, Response.class);if (httpResult.getCode()==200){//200的時候就直接解析,不可能出現(xiàn)解析異常。因為我們實體基類中傳入的泛型,就是數(shù)據(jù)成功時候的格式return gson.fromJson(response,type);}else {ErrorResponse errorResponse = gson.fromJson(response,ErrorResponse.class);//拋一個自定義ResultException 傳入失敗時候的狀態(tài)碼,和信息throw new ResultException(errorResponse.getCode(),errorResponse.getMsg());}} }2、自定義一個響應(yīng)變換工廠 繼承自 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;}@Overridepublic Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {//返回我們自定義的Gson響應(yīng)體變換器return new GsonResponseBodyConverter<>(gson, type);}@Overridepublic Converter<?, RequestBody> requestBodyConverter(Type type,Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {//返回我們自定義的Gson響應(yīng)體變換器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) {//網(wǎng)絡(luò)錯誤_onError(-9999);} else if (e instanceof ResultException) {//自定義的ResultException//由于返回200,300返回格式不統(tǒng)一的問題,自定義GsonResponseBodyConverter凡是300的直接拋異常_onError(((ResultException) e).getErrCode());System.out.println("---------errorCode------->"+((ResultException) e).getErrCode());} }這次是真的完成了我們的json數(shù)據(jù)解析異常的處理,其實我們的解決辦法是解析了兩次,第一次解析的時候我們的Response中只有只是解析了最外層的 code 和 msg ,result中的是沒有解析的。response中的code==200,直接將數(shù)據(jù)解析到我們的實體基類中。如果code!=200時,直接拋自定義的異常,直接會回調(diào)到subscriber中的onError()中。雖然進行了兩次解析,但是第一次只是解析了code,和msg 對于效率的影響其實并不大,在功能實現(xiàn)的基礎(chǔ)上一點點效率的影響(而且這個影響是微乎其微的-.-)其實無傷大雅的。
原文發(fā)布時間為:2018-07-11
本文來自云棲社區(qū)合作伙伴“安卓巴士Android開發(fā)者門戶”,了解相關(guān)信息可以關(guān)注“安卓巴士Android開發(fā)者門戶”。
總結(jié)
以上是生活随笔為你收集整理的Rxjava、Retrofit返回json数据解析异常处理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【漫画解读银行业务】
- 下一篇: 如何利用vw+rem进行移动端布局