欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺談RxJava處理業(yè)務異常的幾種方式

 更新時間:2017年11月09日 14:13:42   作者:fengzhizi715  
本篇文章主要介紹了淺談RxJava處理業(yè)務異常的幾種方式,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

本文介紹了RxJava處理業(yè)務異常的幾種方式,分享給大家。具體如下:

關于異常

Java的異??梢苑譃閮煞N:運行時異常和檢查性異常。

運行時異常:

RuntimeException類及其子類都被稱為運行時異常,這種異常的特點是Java編譯器不去檢查它,也就是說,當程序中可能出現(xiàn)這類異常時,即使沒有用try...catch語句捕獲它,也沒有用throws字句聲明拋出它,還是會編譯通過。

檢查性異常:

除了RuntimeException及其子類以外,其他的Exception類及其子類都屬于檢查性異常。檢查性異常必須被顯式地捕獲或者傳遞。當程序中可能出現(xiàn)檢查性異常時,要么使用try-catch語句進行捕獲,要么用throws子句拋出,否則編譯無法通過。

處理業(yè)務異常

業(yè)務異常:

指的是正常的業(yè)務處理時,由于某些業(yè)務的特殊要求而導致處理不能繼續(xù)所拋出的異常。在業(yè)務層或者業(yè)務的處理方法中拋出異常,在表現(xiàn)層中攔截異常,以友好的方式反饋給使用者,以便其可以依據(jù)提示信息正確的完成任務功能的處理。

1. 重試

不是所有的錯誤都需要立馬反饋給用戶,比如說在弱網(wǎng)絡環(huán)境下調用某個接口出現(xiàn)了超時的現(xiàn)象,也許再請求一次接口就能獲得數(shù)據(jù)。那么重試就相當于多給對方一次機會。

在這里,我們使用retryWhen操作符,它將錯誤傳遞給另一個被觀察者來決定是否要重新給訂閱這個被觀察者。

聽上去有點拗口,直接上代碼吧。

 /**
  * 獲取內容
  * @param fragment
  * @param param
  * @param cacheKey
  * @return
  */
 public Maybe<ContentModel> getContent(Fragment fragment, ContentParam param, String cacheKey) {

  if (apiService == null) {
   apiService = RetrofitManager.get().apiService();
  }

  return apiService.loadContent(param)
    .retryWhen(new RetryWithDelay(3,1000))
    .compose(RxLifecycle.bind(fragment).<ContentModel>toLifecycleTransformer())
    .compose(RxUtils.<ContentModel>toCacheTransformer(cacheKey));
 }

這個例子是一個網(wǎng)絡請求,compose的內容可以忽略。如果網(wǎng)絡請求失敗的話,會調用retryWhen操作符。RetryWithDelay實現(xiàn)了Function接口,RetryWithDelay是一個重試的機制,包含了重試的次數(shù)和重試時間隔的時間。

import com.safframework.log.L;

import org.reactivestreams.Publisher;

import java.util.concurrent.TimeUnit;

import io.reactivex.Flowable;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.Function;

/**
 * 重試機制
 * Created by tony on 2017/11/6.
 */

public class RetryWithDelay implements Function<Flowable<? extends Throwable>, Publisher<?>> {

 private final int maxRetries;
 private final int retryDelayMillis;
 private int retryCount;

 public RetryWithDelay(final int maxRetries, final int retryDelayMillis) {
  this.maxRetries = maxRetries;
  this.retryDelayMillis = retryDelayMillis;
  this.retryCount = 0;
 }

 @Override
 public Publisher<?> apply(@NonNull Flowable<? extends Throwable> attempts) throws Exception {

  return attempts.flatMap(new Function<Throwable, Publisher<?>>() {
   @Override
   public Publisher<?> apply(Throwable throwable) throws Exception {
    if (++retryCount <= maxRetries) {

     L.i("RetryWithDelay", "get error, it will try after " + retryDelayMillis
       + " millisecond, retry count " + retryCount);
     // When this Observable calls onNext, the original
     // Observable will be retried (i.e. re-subscribed).
     return Flowable.timer(retryDelayMillis, TimeUnit.MILLISECONDS);

    } else {

     // Max retries hit. Just pass the error along.
     return Flowable.error(throwable);
    }
   }
  });
 }
}

如果運氣好重試成功了,那用戶在無感知的情況下可以繼續(xù)使用產品。如果多次重試都失敗了,那么必須在onError時做一些異常的處理,提示用戶可能是網(wǎng)絡的原因了。

2. 返回一個默認值

有時出錯只需返回一個默認值,有點類似Java 8 Optional的orElse()

RetrofitManager.get()
    .adService()
    .vmw(param)
    .compose(RxLifecycle.bind(fragment).<VMWModel>toLifecycleTransformer())
    .subscribeOn(Schedulers.io())
    .onErrorReturn(new Function<Throwable, VMWModel>() {
     @Override
     public VMWModel apply(Throwable throwable) throws Exception {
      return new VMWModel();
     }
    });

上面的例子使用了onErrorReturn操作符,表示當發(fā)生錯誤的時候,發(fā)射一個默認值然后結束數(shù)據(jù)流。所以 Subscriber 看不到異常信息,看到的是正常的數(shù)據(jù)流結束狀態(tài)。

跟它類似的還有onErrorResumeNext操作符,表示當錯誤發(fā)生的時候,使用另外一個數(shù)據(jù)流繼續(xù)發(fā)射數(shù)據(jù)。在返回的被觀察者中是看不到錯誤信息的。

使用了onErrorReturn之后,onError是不是就不做處理了?onErrorReturn的確是返回了一個默認值,如果onErrorReturn之后還有類似doOnNext的操作,并且doOnNext中出錯的話,onError還是會起作用的。

曾經遇到過一個復雜的業(yè)務場景,需要多個網(wǎng)絡請求合并結果。這時,我使用zip操作符,讓請求并行處理,等所有的請求完了之后再進行合并操作。某些請求失敗的話,我使用了重試機制,某些請求失敗的話我給了默認值。

3. 使用onError處理異常

現(xiàn)在的Android開發(fā)中,網(wǎng)絡框架是Retrofit的天下。在接口定義的返回類型中,我一般喜歡用Maybe、Completable來代替Observable。

我們知道RxJava在使用時,觀察者會調用onNext、onError、onComplete方法,其中onError方法是事件在傳遞或者處理的過程中發(fā)生錯誤后會調用到。

下面的代碼,分別封裝兩個基類的Observer,都重寫了onError方法用于處理各種網(wǎng)絡異常。這兩個基類的Observer是在使用Retrofit時使用的。

封裝一個BaseMaybeObserver

import android.accounts.NetworkErrorException
import android.content.Context

import com.safframework.log.L
import io.reactivex.observers.DisposableMaybeObserver
import java.net.ConnectException
import java.net.SocketTimeoutException
import java.net.UnknownHostException

/**
 * Created by Tony Shen on 2017/8/8.
 */
abstract class BaseMaybeObserver<T> : DisposableMaybeObserver<T>() {

 internal var mAppContext: Context

 init {
  mAppContext = AppUtils.getApplicationContext()
 }

 override fun onSuccess(data: T) {
  onMaybeSuccess(data)
 }

 abstract fun onMaybeSuccess(data: T)

 override fun onError(e: Throwable) {
  var message = e.message
  L.e(message)

  when(e) {

   is ConnectException -> message = mAppContext.getString(R.string.connect_exception_error)
   is SocketTimeoutException -> message = mAppContext.getString(R.string.timeout_error)
   is UnknownHostException -> message = mAppContext.getString(R.string.network_error)
   is NetworkErrorException -> message = mAppContext.getString(R.string.network_error)
   else -> message = mAppContext.getString(R.string.something_went_wrong)
  }

  RxBus.get().post(FailedEvent(message))
 }

 override fun onComplete() {}
}

封裝一個BaseCompletableObserver

import android.accounts.NetworkErrorException
import android.content.Context

import com.safframework.log.L
import io.reactivex.observers.ResourceCompletableObserver
import java.net.ConnectException
import java.net.SocketTimeoutException
import java.net.UnknownHostException

/**
 * Created by Tony Shen on 2017/8/8.
 */
abstract class BaseCompletableObserver : ResourceCompletableObserver() {

 internal var mAppContext: Context

 init {
  mAppContext = AppUtils.getApplicationContext()
 }

 override fun onComplete() {
  onSuccess()
 }

 abstract fun onSuccess()

 override fun onError(e: Throwable) {
  var message = e.message
  L.e(message)

  when(e) {

   is ConnectException -> message = mAppContext.getString(R.string.connect_exception_error)
   is SocketTimeoutException -> message = mAppContext.getString(R.string.timeout_error)
   is UnknownHostException -> message = mAppContext.getString(R.string.network_error)
   is NetworkErrorException -> message = mAppContext.getString(R.string.network_error)
   else -> message = mAppContext.getString(R.string.something_went_wrong)
  }

  RxBus.get().post(FailedEvent(message))
 }
}

在這里用到了Kotlin來寫這兩個基類,使用Kotlin的目的是因為代碼更加簡潔,避免使用switch或者各種if(XX instancof xxException)來判斷異常類型,可以跟Java代碼無縫結合。

下面的代碼展示了如何使用BaseMaybeObserver,即使遇到異常BaseMaybeObserver的onError也會做相應地處理。如果有特殊的需求,也可以重寫onError方法。

    model.getContent(VideoFragment.this,param, cacheKey)
      .compose(RxJavaUtils.<ContentModel>maybeToMain())
      .doFinally(new Action() {
       @Override
       public void run() throws Exception {
        refreshlayout.finishRefresh();
       }
      })
      .subscribe(new BaseMaybeObserver<ContentModel>(){

     @Override
     public void onMaybeSuccess(ContentModel data) {
      adpter.addDataToFront(data);
     }
    });

4. 內部異常使用責任鏈模式來分發(fā)

這是微信中一位網(wǎng)友提供的方法,他做了一個很有意思的用于異常分發(fā)的一個庫,github地址:https://github.com/vihuela/Retrofitplus

內部異常使用責任鏈分發(fā),分發(fā)邏輯為:

  1. 自定義異常->網(wǎng)絡異常->服務器異常->內部程序異常->未知異常
  2. 除了以上自定義異常之外,此庫包含其它異常分發(fā),默認適應場景為:Rx+Json
  3. 自定義異常使用請調用,ExceptionParseMgr類的addCustomerParser方法添加業(yè)務異常

這個庫對原先的代碼無侵入性。此外,他還提供了另一種思路,結合compose來處理一些特定的業(yè)務異常。

總結

本文僅僅是總結了個人使用RxJava遇到業(yè)務異常的情況,并對此做了一些相應地處理,肯定是不能覆蓋開發(fā)的方方面面,僅作為拋磚引玉,如果有更好、更優(yōu)雅的處理方式,一定請告知。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

最新評論