Android RxJava+Retrofit統(tǒng)一處理API

假設(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();? ? }}

就這樣吧濒翻,有興趣的看看代碼屁柏,不清楚的或者有不足的地方,歡迎交流有送。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末淌喻,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子娶眷,更是在濱河造成了極大的恐慌似嗤,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件届宠,死亡現(xiàn)場(chǎng)離奇詭異乖篷,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)诉稍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門揉忘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人轧铁,你說(shuō)我怎么就攤上這事每聪。” “怎么了齿风?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵药薯,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我救斑,道長(zhǎng)童本,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任脸候,我火速辦了婚禮穷娱,結(jié)果婚禮上绑蔫,老公的妹妹穿的比我還像新娘。我一直安慰自己泵额,他們只是感情好配深,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著嫁盲,像睡著了一般篓叶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上亡资,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天澜共,我揣著相機(jī)與錄音,去河邊找鬼锥腻。 笑死嗦董,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的瘦黑。 我是一名探鬼主播京革,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼幸斥!你這毒婦竟也來(lái)了匹摇?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤甲葬,失蹤者是張志新(化名)和其女友劉穎廊勃,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體经窖,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡坡垫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了画侣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片冰悠。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖配乱,靈堂內(nèi)的尸體忽然破棺而出溉卓,到底是詐尸還是另有隱情,我是刑警寧澤搬泥,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布桑寨,位于F島的核電站,受9級(jí)特大地震影響忿檩,放射性物質(zhì)發(fā)生泄漏西疤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一休溶、第九天 我趴在偏房一處隱蔽的房頂上張望代赁。 院中可真熱鬧,春花似錦兽掰、人聲如沸芭碍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)窖壕。三九已至,卻和暖如春杉女,著一層夾襖步出監(jiān)牢的瞬間瞻讽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工熏挎, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留速勇,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓坎拐,卻偏偏與公主長(zhǎng)得像烦磁,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子哼勇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容