Retrofit+RxJava 優(yōu)雅的處理服務(wù)器返回異常、錯(cuò)誤_第1頁(yè)
Retrofit+RxJava 優(yōu)雅的處理服務(wù)器返回異常、錯(cuò)誤_第2頁(yè)
Retrofit+RxJava 優(yōu)雅的處理服務(wù)器返回異常、錯(cuò)誤_第3頁(yè)
Retrofit+RxJava 優(yōu)雅的處理服務(wù)器返回異常、錯(cuò)誤_第4頁(yè)
Retrofit+RxJava 優(yōu)雅的處理服務(wù)器返回異常、錯(cuò)誤_第5頁(yè)
已閱讀5頁(yè),還剩9頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、Retrofit+RxJava 優(yōu)雅的處理服務(wù)器返回異常、錯(cuò)誤異常&錯(cuò)誤實(shí)際開發(fā)經(jīng)常有這種情況,比如登錄請(qǐng)求,接口返回的 信息包括請(qǐng)求返回的狀態(tài):失敗還是成功,錯(cuò)誤碼,User對(duì)象等等。如果網(wǎng)絡(luò)等原因引起的登錄失敗可以歸結(jié)為異常,如果是用戶信息輸入錯(cuò)誤導(dǎo)致的登錄失敗算是錯(cuò)誤。假如服務(wù)器返回的是統(tǒng)一數(shù)據(jù)格式:/* * 標(biāo)準(zhǔn)數(shù)據(jù)格式 * param <T> */public class Response<T> public int state; public String message; public T data;網(wǎng)絡(luò)異常導(dǎo)致的登錄失敗,在使用Retrofit+

2、RxJava請(qǐng)求時(shí)都會(huì)直接調(diào)用subscribe的onError事件;密碼錯(cuò)誤導(dǎo)致的登錄失敗,在使用Retrofit+RxJava請(qǐng)求時(shí)都會(huì)調(diào)用subscribe的onNext事件;無(wú)論是異常還是錯(cuò)誤,都要在subscribe里面處理異常信息,如下代碼:APIWrapper.getInstance().login("username", "password") .subscribe(new Observer<Response<User>>() Override public void onCompleted() Override

3、public void onError(Throwable e) Override public void onNext(Response<User> data) if(data.state = 1001) /. else if(data.state = 1002) );現(xiàn)在我希望在發(fā)生任何錯(cuò)誤的情況下,都會(huì)調(diào)用onError事件,并且由model來(lái)處理錯(cuò)誤信息。那么,此時(shí)我們就應(yīng)該有一個(gè)ExceptionEngine來(lái)處理事件流中的錯(cuò)誤信息了。在工作流中處理異常在正常情況下,我們獲取網(wǎng)絡(luò)數(shù)據(jù)的流程通常如下:請(qǐng)求接口->解析數(shù)據(jù)->更新整個(gè)數(shù)據(jù)請(qǐng)求過程都是發(fā)生在Rx中的

4、工作流之中。當(dāng)有異常產(chǎn)生的時(shí)候,我們要盡量不在ui層里面進(jìn)行判斷,換句話說,我們沒有必要去告訴ui層具體的錯(cuò)誤信息,只需要讓他彈出一個(gè)信息(Toast或者Dialog)展示我們給它的信息就行。請(qǐng)求接口和數(shù)據(jù)解析都可能出錯(cuò),所以在這兩層進(jìn)行錯(cuò)誤處理。為了更好的解耦,我們通過攔截器攔截錯(cuò)誤,然后根據(jù)錯(cuò)誤類型分發(fā)信息。攔截器數(shù)據(jù)解析層的攔截器這個(gè)攔截器主要是為了獲取具體的錯(cuò)誤信息,分發(fā)給上層的UI,給用戶以提示,增強(qiáng)用戶體驗(yàn)。public Observable<Weather> getWeather(String cityName) return weatherService.getWe

5、ather(cityName) /攔截服務(wù)器返回的錯(cuò)誤 .map(new ServerResponseFunc<Weather>() /HttpResultFunc()為攔截onError事件的攔截器,后面會(huì)講到,這里先忽略 .onErrorResumeNext(new HttpResponseFunc<Weather>(); /攔截固定格式的公共數(shù)據(jù)類型Response<T>,判斷里面的狀態(tài)碼private class ServerResponseFunc<T> implements Func1<Response<T>, T&

6、gt; Override public T call(Response<T> reponse) /對(duì)返回碼進(jìn)行判斷,如果不是0,則證明服務(wù)器端返回錯(cuò)誤信息了,便根據(jù)跟服務(wù)器約定好的錯(cuò)誤碼去解析異常 if (reponse.state != 0) /如果服務(wù)器端有錯(cuò)誤信息返回,那么拋出異常,讓下面的方法去捕獲異常做統(tǒng)一處理 throw new ServerException(reponse.state,reponse.message); /服務(wù)器請(qǐng)求數(shù)據(jù)成功,返回里面的數(shù)據(jù)實(shí)體 return reponse.data; 所以整個(gè)邏輯是這樣的: 所以在前三步的過程中,只要發(fā)生異常(服務(wù)

7、器返回的錯(cuò)誤也拋出了)都會(huì)拋出,這時(shí)候就觸發(fā)了RxJava的OnError事件。處理onError事件的攔截器這個(gè)攔截器主要是將異常信息轉(zhuǎn)化為用戶”能看懂”的友好提示。 private class HttpResponseFunc<T> implements Func1<Throwable, Observable<T>> Override public Observable<T> call(Throwable throwable) /ExceptionEngine為處理異常的驅(qū)動(dòng)器 return Observable.error(Exceptio

8、nEngine.handleException(throwable); 兩個(gè)攔截器以前使用,代碼如下:public Observable<Weather> getWeather(String cityName) return weatherService.getWeather(cityName) /攔截服務(wù)器返回的錯(cuò)誤 .map(new ServerResponseFunc<Weather>() /HttpResponseFunc()為攔截onError事件的攔截器 .onErrorResumeNext(new HttpResponseFunc<Weather&g

9、t;(); 調(diào)用:APIWrapper.getInstance().getWeather("北京") .subscribe(new SampleProgressObserver<Weather>(MainActivity.this) Override public void onNext(WeatherBean weatherBean) tv.setText(weatherBean.toString(); );相關(guān)類:public class RxSubscriber<T> extends ErrorSubscriber<T> Overr

10、ide public void onStart() super.onStart(); DialogHelper.showProgressDlg(context, "正在加載數(shù)據(jù)"); Override public void onCompleted() DialogHelper.stopProgressDlg(); Override protected void onError(ApiException ex) DialogHelper.stopProgressDlg(); Toast.makeText(context, ex.message, Toast.LENGTH_S

11、HORT).show(); Override public void onNext(T t) public abstract class ErrorSubscriber<T> extends Observer<T> Override public void onError(Throwable e) if(e instanceof ApiException) onError(ApiException)e); else onError(new ApiException(e,123); /* * 錯(cuò)誤回調(diào) */ protected abstract void onError(

12、ApiException ex);處理異常的驅(qū)動(dòng)器package ;import .ParseException;import com.google.gson.JsonParseException;import org.json.JSONException;import .ConnectException;import retrofit2.adapter.rxjava.HttpException;/* * Created by Lzx on 2016/7/11. */public class ExceptionEngine /對(duì)應(yīng)HTTP的狀態(tài)碼 private static final in

13、t UNAUTHORIZED = 401; private static final int FORBIDDEN = 403; private static final int NOT_FOUND = 404; private static final int REQUEST_TIMEOUT = 408; private static final int INTERNAL_SERVER_ERROR = 500; private static final int BAD_GATEWAY = 502; private static final int SERVICE_UNAVAILABLE = 5

14、03; private static final int GATEWAY_TIMEOUT = 504; public static ApiException handleException(Throwable e) ApiException ex; if (e instanceof HttpException) /HTTP錯(cuò)誤 HttpException httpException = (HttpException) e; ex = new ApiException(e, ERROR.HTTP_ERROR); switch(httpException.code() case UNAUTHORI

15、ZED: case FORBIDDEN: case NOT_FOUND: case REQUEST_TIMEOUT: case GATEWAY_TIMEOUT: case INTERNAL_SERVER_ERROR: case BAD_GATEWAY: case SERVICE_UNAVAILABLE: default: ex.message = "網(wǎng)絡(luò)錯(cuò)誤" /均視為網(wǎng)絡(luò)錯(cuò)誤 break; return ex; else if (e instanceof ServerException) /服務(wù)器返回的錯(cuò)誤 ServerException resultException

16、= (ServerException) e; ex = new ApiException(resultException, resultException.code); ex.message = resultException.message; return ex; else if (e instanceof JsonParseException | e instanceof JSONException | e instanceof ParseException) ex = new ApiException(e, ERROR.PARSE_ERROR); ex.message = "解

17、析錯(cuò)誤" /均視為解析錯(cuò)誤 return ex; else if(e instanceof ConnectException) ex = new ApiException(e, ERROR.NETWORD_ERROR); ex.message = "連接失敗" /均視為網(wǎng)絡(luò)錯(cuò)誤 return ex; else ex = new ApiException(e, ERROR.UNKNOWN); ex.message = "未知錯(cuò)誤" /未知錯(cuò)誤 return ex; /* * 約定異常 */public class ERROR /* * 未知錯(cuò)誤

18、*/ public static final int UNKNOWN = 1000; /* * 解析錯(cuò)誤 */ public static final int PARSE_ERROR = 1001; /* * 網(wǎng)絡(luò)錯(cuò)誤 */ public static final int NETWORD_ERROR = 1002; /* * 協(xié)議出錯(cuò) */ public static final int HTTP_ERROR = 1003;public class ApiException extends Exception public int code; public String message; pu

19、blic ApiException(Throwable throwable, int code) super(throwable); this.code = code; public class ServerException extends RuntimeException public int code; public String message;DialogHelper.Javapublic class DialogHelper /* * 通用Dialog * */ / 因?yàn)楸绢惒皇莂ctivity所以通過繼承接口的方法獲取到點(diǎn)擊的事件 public interface OnOkCli

20、ckListener abstract void onOkClick(); /* * Listener */ public interface OnCancelClickListener abstract void onCancelClick(); private static AlertDialog mDialog; public static void showDialog(Context context, String title, String content, final OnOkClickListener listenerYes, final OnCancelClickListen

21、er listenerNo) showDialog(context, context.getString(android.R.string.ok), context.getString(android.R.string.cancel), title, content, listenerYes, listenerNo); public static void showDialog(Context context, String ok, String cancel, String title, String content, final OnOkClickListener listenerYes,

22、 final OnCancelClickListener listenerNo) AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setMessage(content); / 設(shè)置title builder.setTitle(title); / 設(shè)置確定按鈕,固定用法聲明一個(gè)按鈕用這個(gè)setPositiveButton builder.setPositiveButton(ok, new DialogInterface.OnClickListener() public void onClick(Dia

23、logInterface dialog, int which) / 如果確定被電擊 if (listenerYes != null) listenerYes.onOkClick(); mDialog = null; ); / 設(shè)置取消按鈕,固定用法聲明第二個(gè)按鈕要用setNegativeButton builder.setNegativeButton(cancel, new DialogInterface.OnClickListener() public void onClick(DialogInterface dialog, int which) / 如果取消被點(diǎn)擊 if (listener

24、No != null) listenerNo.onCancelClick(); mDialog = null; ); / 控制這個(gè)dialog可不可以按返回鍵,true為可以,false為不可以 builder.setCancelable(false); / 顯示dialog mDialog = builder.create(); if (!mDialog.isShowing() mDialog.show(); public static void showDialog(Context context, int ok, int cancel, int title, int content, f

25、inal OnOkClickListener listenerYes, final OnCancelClickListener listenerNo) showDialog(context, context.getString(ok), context.getString(cancel), context.getString(title), context.getString(content), listenerYes, listenerNo); static ProgressDialog progressDlg = null; /* * 啟動(dòng)進(jìn)度條 * * param strMessage

26、進(jìn)度條顯示的信息 * param / 當(dāng)前的activity */ public static void showProgressDlg(Context ctx, String strMessage) if (null = progressDlg) if (ctx = null) return; progressDlg = new ProgressDialog(ctx); /設(shè)置進(jìn)度條樣式 progressDlg.setProgressStyle(ProgressDialog.STYLE_SPINNER); /提示的消息 progressDlg.setMessage(strMessage);

27、progressDlg.setIndeterminate(false); progressDlg.setCancelable(true); progressDlg.show(); public static void showProgressDlg(Context ctx) showProgressDlg(ctx, ""); /* * 結(jié)束進(jìn)度條 */ public static void stopProgressDlg() if (null != progressDlg && progressDlg.isShowing() progressDlg.dism

28、iss(); progressDlg = null; if (null != dialog && dialog.isShowing() dialog.dismiss(); dialog = null; private static Dialog dialog; public static void showDialogForLoading(Context context, String msg, boolean cancelable) if (null = dialog) if (null = context) return; View view = LayoutInflate

29、r.from(context).inflate(R.layout.layout_loading_dialog, null); TextView loadingText = (TextView)view.findViewById(R.id.loading_tip_text); loadingText.setText(msg); dialog = new Dialog(context, R.style.loading_dialog_style); dialog.setCancelable(cancelable); dialog.setCanceledOnTouchOutside(cancelabl

30、e); dialog.setContentView(iew, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT); Activity activity = (Activity) context; if (activity.isFinishing() return; dialog.show(); 可能本博客也不是最好的解決方案,如果有更好的想法,我愿與你互相交流!分享: Retrofit+RxJava錯(cuò)誤預(yù)處理看到bobo_wan

31、g的文章,不僅感覺有受益匪淺,這里做下介紹。首先定義如下Transformer轉(zhuǎn)換器。public static <T> Observable.Transformer<Response<T>, T> sTransformer() return responseObservable -> responseObservable.map(tResponse -> if (!tResponse.success) throw new RuntimeException(tResponse.code); return tRata; ).onErrorResum

32、eNext(new HttpResponseFunc<>(); public static <T> Observable.Transformer<T, T> switchSchedulers() return observable -> observable.subscribeOn(Schedulers.io() .observeOn(AndroidSchedulers.mainThread(); private static class HttpResponseFunc<T> implements Func1<Throwable,

33、Observable<T>> Override public Observable<T> call(Throwable throwable) /ExceptionEngine為處理異常的驅(qū)動(dòng)器 return Observable.error(new Throwable(throwable); 調(diào)用:public void login(View v) apiservice.login(name,pwd) .compose(Transformers.sTransformer() .compose(Transformers.switchSchedulers() .sub

34、scribe(subscriber);private Subscriber<UserModel> subscriber = new Subscriber<UserModel>() Override public void onCompleted() / do onCompleted Override public void onError(Throwable e) / do on success != true; / do on http error / do on other error Override public void onNext(UserModel mo

35、del) / parse data ;接口:FormUrlEncoded POST("interface?login")Observable<Response<UserModel>> login(Field("name") String name,Field("pwd") String pwd);最后再來(lái)點(diǎn)干貨。Transformer 和 Func 處理的區(qū)別如上的處理,定義了 一個(gè) sTransformer 和一個(gè) HttpResponseFunc, 從中可以明顯感覺的到sTransformer其實(shí)也是可以用

36、Func1來(lái)定義的,public void login(View v) apiservice.login(name,pwd) .compose(Transformers.switchSchedulers() .map(new TransFuc<UserModel>() .onErrorReturn(new HttpResponseFunc<>() .subscribe(subscriber);public static class TransFuc<T> implements Func1<Response<T>, T> Override public T call(Response<T> tResponse) if (!tResponse.success) throw new RuntimeException(tResponse.code); return tRe

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論