假設(shè)有個(gè)登錄API,登錄返回的值是
{"code":0,msg:"登錄成功","data":{"username":"xxx","nikename":"xxx"...}}
{"code":-100,msg:"用戶不存在","data":null}
{"code":-101,msg:"密碼錯(cuò)誤","data":null}
...
用其他框架Http請(qǐng)求的時(shí)候美莫,比如默認(rèn)回調(diào)是HttpCallback额衙,我們一般會(huì)對(duì)這個(gè)HttpCallback加一層封裝比如MyHttpCallback染乌,在MyHttpCallback里面
1) JSON轉(zhuǎn)成Bean //也有很多框架自帶Gson
2) code<0的時(shí)候彈出一個(gè)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種情況:
第一種是連接服務(wù)端失敗(比如常見的404帐要、500殿衰、502等)
第二種是請(qǐng)求成功但服務(wù)端告知我們參數(shù)有誤
第三種是完全正確的
那使用RxJava+Retrofit該如何寫出效果類似MyHttpCallback的功能呢?
1) 一般第一反應(yīng)就是在Subscriber的onNext里面去判斷蛤克,這樣的寫法滿足不了這樣的需求:code<0的時(shí)候要Retry
2) Retrofit我們都采用Gson處理返回的數(shù)據(jù),如果我返回的結(jié)果比較簡(jiǎn)單夷蚊,比如根據(jù)手機(jī)號(hào)返回一個(gè)驗(yàn)證碼{"code":0,msg:"獲取驗(yàn)證碼成功","data":"8451"}构挤,還是要建立一個(gè)Bean類,有點(diǎn)麻煩惕鼓,我想不寫這個(gè)Bean類筋现,在onNext傳入的參數(shù)可不可以直接是JSONObject或者String
3) 我們會(huì)經(jīng)常在onNext里面去處理UI,那我們應(yīng)該知道需要在Activity的onDestroy()取消訂閱。第一想法就是在Activity聲明一個(gè)全局變量
privateCompositeSubscription compositeSubscription;
每次訂閱的時(shí)候都添加到compositeSubscription
Subscription subscription = xxx
? ? ? ? .xxx()
? ? ? ? .retryWhen(xxx)
? ? ? ? .subscribeOn(Schedulers.io())
? ? ? ? .observeOn(AndroidSchedulers.mainThread());?
? ? ? ? .subscribe(xxx);
compositeSubscription.add(subscription);
然后在onDestroy()里面
compositeSubscription.unsubscribe();
這樣寫法沒(méi)什么問(wèn)題矾飞,只是每次訂閱都要重復(fù)這2句
Subscription subscription = xxx;
compositeSubscription.add(subscription);
不是鏈?zhǔn)搅艘慌颍缓每础?/p>
4) 我們的項(xiàng)目里應(yīng)該有很多公共的部分
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
比如我的項(xiàng)目里這部分都是一樣的,每個(gè)請(qǐng)求都寫這么長(zhǎng)一串也不太好看洒沦。
直接上代碼豹绪,看看最終的寫法
publicclassMainActivityextendsBaseActivityimplementsView.OnClickListener{@OverrideprotectedvoidonCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);? ? ? ? setContentView(R.layout.activity_main);? ? }@OverridepublicvoidonClick(View view){? ? ? ? DX168API.get()? ? ? ? ? ? ? ? .login("xxx","xxx")? ? ? ? ? ? ? ? .retryWhen(newRetryWhenNetworkException())//可以設(shè)置重試次數(shù),延遲重試.compose(newDX168Transformer())//一些通用的處理申眼,如subscribeOn和observeOn.lift(newBindActivityOperator(this))//綁定Activity瞒津,可以指定Activity的生命周期,用來(lái)取消訂閱.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) {//如果返回結(jié)果是JSONObject或者DX168Response則無(wú)需經(jīng)過(guò)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時(shí)Toast顯示msgthrownewDX168Exception(code, msg, value);? ? ? ? ? ? }? ? ? ? }catch(JSONException e) {//服務(wù)端返回的不是JSON括尸,服務(wù)端出問(wèn)題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,"網(wǎng)絡(luò)較慢巷蚪,請(qǐng)稍候...", 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) {//如果超出重試次數(shù)也拋出錯(cuò)誤,否則默認(rèn)是會(huì)進(jìn)入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();? ? }}
就這樣吧濒翻,有興趣的看看代碼屁柏,不清楚的或者有不足的地方,歡迎交流有送。