假设有个登录API,登录返回的值是
{"code":0,msg:"登录成功","data":{"username":"xxx","nikename":"xxx"...}}
{"code":-100,msg:"用户不存在","data":null}
{"code":-101,msg:"密码错误","data":null}
...
用其他框架Http请求的时候,比如默认回调是HttpCallback,我们一般会对这个HttpCallback加一层封装比如MyHttpCallback,在MyHttpCallback里面
1) JSON转成Bean //也有很多框架自带Gson
2) code<0的时候弹出一个Toast显示msg
OkHttpUtils .get() .url("http://xxx") .addParams("username","xxx") .addParams("password","xxx") .build() .execute(newMyHttpCallback() {@OverridepublicvoidonError(Exception e){ }@OverridepublicvoidonFailure(intcode, String msg){ }@OverridepublicvoidonSuccess(intcode, String msg, User user){ } });
返回分为3种情况:
第一种是连接服务端失败(比如常见的404、500、502等)
第二种是请求成功但服务端告知我们参数有误
第三种是完全正确的
那使用RxJava+Retrofit该如何写出效果类似MyHttpCallback的功能呢?
1) 一般第一反应就是在Subscriber的onNext里面去判断,这样的写法满足不了这样的需求:code<0的时候要Retry
2) Retrofit我们都采用Gson处理返回的数据,如果我返回的结果比较简单,比如根据手机号返回一个验证码{"code":0,msg:"获取验证码成功","data":"8451"},还是要建立一个Bean类,有点麻烦,我想不写这个Bean类,在onNext传入的参数可不可以直接是JSONObject或者String
3) 我们会经常在onNext里面去处理UI,那我们应该知道需要在Activity的onDestroy()取消订阅。第一想法就是在Activity声明一个全局变量
privateCompositeSubscription compositeSubscription;
每次订阅的时候都添加到compositeSubscription
Subscription subscription = xxx
.xxx()
.retryWhen(xxx)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
.subscribe(xxx);
compositeSubscription.add(subscription);
然后在onDestroy()里面
compositeSubscription.unsubscribe();
这样写法没什么问题,只是每次订阅都要重复这2句
Subscription subscription = xxx;
compositeSubscription.add(subscription);
不是链式了,不好看。
4) 我们的项目里应该有很多公共的部分
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
比如我的项目里这部分都是一样的,每个请求都写这么长一串也不太好看。
直接上代码,看看最终的写法
publicclassMainActivityextendsBaseActivityimplementsView.OnClickListener{@OverrideprotectedvoidonCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); }@OverridepublicvoidonClick(View view){ DX168API.get() .login("xxx","xxx") .retryWhen(newRetryWhenNetworkException())//可以设置重试次数,延迟重试.compose(newDX168Transformer())//一些通用的处理,如subscribeOn和observeOn.lift(newBindActivityOperator(this))//绑定Activity,可以指定Activity的生命周期,用来取消订阅.subscribe(newDX168Subscriber(getApplicationContext()) {@OverridepublicvoidonSuccess(User user){//TODO} }); DX168API.get() .getRegisterVerifyCode("18888888888") .retryWhen(newRetryWhenNetworkException()) .compose(newDX168Transformer()) .lift(newBindActivityOperator(this)) .subscribe(newDX168Subscriber(getApplicationContext()) {@OverridepublicvoidonSuccess(String data){//TODO// data就是verifyCode} }); }}
publicclassDX168GsonResponseBodyConverterimplementsConverter{privatefinalGson gson;privatefinalType type; DX168GsonResponseBodyConverter(Gson gson, Type type) {this.gson = gson;this.type = type; }@OverridepublicTconvert(ResponseBody responseBody)throwsIOException{ String value = responseBody.string();try{ JSONObject response =newJSONObject(value);intcode = response.optInt("code"); String msg = response.optString("msg");if(code == DX168API.RESULT_OK) {//如果返回结果是JSONObject或者DX168Response则无需经过Gsonif(type.toString().equals(JSONObject.class.toString())) {return(T) response; }elseif(type.toString().equals(DX168Response.class.toString())) { Object data = response.opt("data"); DX168Response dx168Response =newDX168Response(code, msg, data);return(T) dx168Response; }else{returngson.fromJson(value, type); } }else{//返回的code不是RESULT_OK时Toast显示msgthrownewDX168Exception(code, msg, value); } }catch(JSONException e) {//服务端返回的不是JSON,服务端出问题thrownewDX168Exception(-1,"", value); } }}
publicabstractclassDX168SubscriberextendsSubscriber{privateContext context;publicDX168Subscriber(Context applicationContext){this.context = applicationContext.getApplicationContext(); }@OverridepublicvoidonError(Throwable throwable){ Throwable e = throwable;while(throwable.getCause() !=null) { e = throwable; throwable = throwable.getCause(); }if(einstanceofConnectException || einstanceofSocketTimeoutException || einstanceofTimeoutException) { onNetworkException(e); }elseif(einstanceofDX168Exception) { onDX168Exception((DX168Exception) e); }else{ onUnknownException(e); } }@OverridepublicvoidonNext(DX168Response dx168Response){ Object data = dx168Response.getData();if(data == JSONObject.NULL) { data =null; } onSuccess((T) data); }publicabstractvoidonSuccess(T data);@OverridepublicvoidonCompleted(){ }publicvoidonDX168Exception(DX168Exception e){ Toast.makeText(context, e.getMessage(), Toast.LENGTH_SHORT).show(); }publicvoidonNetworkException(Throwable e){ Toast.makeText(context,"网络较慢,请稍候...", Toast.LENGTH_SHORT).show(); }publicvoidonUnknownException(Throwable e){ Toast.makeText(context, e.toString(), Toast.LENGTH_SHORT).show(); }}
publicclassRetryWhenNetworkExceptionimplementsFunc1,Observable>{privateintcount =5;privatelongdelay =5000;privatelongincreaseDelay =5000;publicRetryWhenNetworkException(){ }publicRetryWhenNetworkException(intcount,longdelay){this.count = count;this.delay = delay; }publicRetryWhenNetworkException(intcount,longdelay,longincreaseDelay){this.count = count;this.delay = delay;this.increaseDelay = increaseDelay; }@OverridepublicObservable call(Observable observable) {returnobservable .zipWith(Observable.range(1, count +1),newFunc2() {@OverridepublicWrappercall(Throwable throwable, Integer integer){returnnewWrapper(throwable, integer); } }).flatMap(newFunc1>() {@OverridepublicObservable call(Wrapper wrapper) {if((wrapper.throwableinstanceofConnectException || wrapper.throwableinstanceofSocketTimeoutException || wrapper.throwableinstanceofTimeoutException) && wrapper.index < count +1) {//如果超出重试次数也抛出错误,否则默认是会进入onCompletedreturnObservable.timer(delay + (wrapper.index -1) * increaseDelay, TimeUnit.MILLISECONDS); }returnObservable.error(wrapper.throwable); } }); }privateclassWrapper{privateintindex;privateThrowable throwable;publicWrapper(Throwable throwable,intindex){this.index = index;this.throwable = throwable; } }}
publicclassBaseActivityextendsActivity{privateList subscribers;publicvoidaddSubscriber(Subscriber subscriber, ActivityLifecycle unsubscribeOn){if(subscribers ==null) { subscribers =newArrayList<>(); } subscribers.add(newSubscriberWrapper(subscriber, unsubscribeOn)); }privateclassSubscriberWrapper{ Subscriber subscriber; ActivityLifecycle unsubscribeOn;publicSubscriberWrapper(Subscriber subscriber, ActivityLifecycle unsubscribeOn){this.subscriber = subscriber;this.unsubscribeOn = unsubscribeOn; } }@OverrideprotectedvoidonStop(){for(SubscriberWrapper wrapper : subscribers) {if(wrapper.unsubscribeOn == ActivityLifecycle.OnStop) { wrapper.subscriber.unsubscribe(); subscribers.remove(wrapper); } }super.onStop(); }@OverrideprotectedvoidonDestroy(){for(SubscriberWrapper wrapper : subscribers) {if(wrapper.unsubscribeOn == ActivityLifecycle.OnDestroy) { wrapper.subscriber.unsubscribe(); subscribers.remove(wrapper); } }super.onDestroy(); }}
就这样吧,有兴趣的看看代码,不清楚的或者有不足的地方,欢迎交流。
网友评论