2017-05-29 48 views
0

我開發自己的下載用戶數據流,並有問題。 Buyt第一一些代碼,方法說明:錯誤後新單

loginManager.getAccessToken() //Returns Single<String> where string is my access token 
loginManager.getRefreshToken() //Returns Single<String> where string is my refresh token 
loginManager.downloadUserAccountData(String accessToken) //Returns Single<String> where string is my json response 
loginManager.refreshAccessToken(String refreshToken) //Returns Single<String> where string is new access token 
userManager.parseUserJson(String json) //Returns Single<User> where User is my user model 
userManager.storeUser(User user) //Returns Completable 

目前我doning類似的東西:

Completable getAndStoreUserData = loginManager.getAccessToken() 
     .flatMap(loginManager::downloadUserAccountData) 
     .flatMap(userManager::parseUserJson) 
     .flatMapCompletable(userManager::storeUser); 

但是,這並不支持,刷新訪問令牌,然後重試下載。臺服務器上拋出403當我accessToken不是最新的,所以我在那種情況下,我的函數返回錯誤downloadUserAccountData

現在我曾嘗試使用doOnError()onErrorReturn()但兩者本operartors都不滿足我的要求。這是因爲doOnError()只允許例如顯示Log並且不返回任何東西。 onErrorReturn()讓我只返回價值而不是Single<Value>

這是僞代碼我想實現:

Completable getAndStoreUserData = loginManager.getAccessToken() 
     .flatMap(loginManager::downloadUserAccountData) 
     .onErrorReturn(error -> loginManager.getRefreshToken() 
       .flatMap(loginManager::refreshAccessToken) 
       .flatMap(loginManager::downloadUserAccountData) 
     .flatMap(userManager::parseUserJson) 
     .flatMapCompletable(userManager::storeUser); 

任何實例讚賞:)

+0

你使用改造? – Cochi

+0

@科奇不,我不知道。我不能在這個項目中使用Retrofit :( –

回答

1

我終於成功了,該怎麼做。由於@科奇提出我已經使用了retryWhen()函數。這是很簡單的例子基於String爲別人:

String body = null; 

@Override 
protected void onStart() { 
    super.onStart(); 

    Single<String> stringSingle = Single.create(source -> { 
       if(body != null) { 
        source.onSuccess(body); 
       } 
       else { 
        source.onError(new Exception("403")); 
       } 
      }) 
      .retryWhen(errors -> errors.flatMap(error -> { 
       if(error.getMessage().contains("403")) { 
        Throwable throwable = refresh().blockingGet(); 
        if(throwable == null) { 
         return Flowable.just(new Object()); 
        } 
        return Flowable.error(throwable); 
       } 
       return Flowable.error(error); 
      })) 
      .flatMap(obj -> Single.just(obj.toString())); 
} 

public Completable refresh() { 
    return Completable.create(source -> { 
     try { 
      body = "Success"; 
      source.onComplete(); 
     } 
     catch (Exception e) { 
      source.onError(e); 
     } 
    }); 
} 

而且有完整的例子,使用我的代碼:

Completable getAndStoreUserData() {} 
    Completable getAndStoreUserData = loginManager.getAccessToken() 
      .flatMap(loginManager::downloadUserAccountData) 
      .retryWhen(errors -> errors.flatmap(this::retryConditionChecker)) 
      .flatMapCompletable(userManager::storeUser); 

    return getAndStoreUserData 
} 

Publisher<?> retryConditionChecker(Throwable error) { 
    if(error.getMessage().contains("403")) { 

     Throwable throwable = loginManager.getRefreshToken() 
       .flatMap(loginManager::refreshAccessToken) 
       .flatMapCompletable(loginManager::replaceAccessToken) 
       .blockingGet(); 

     if(throwable == null) { 
      return Flowable.just(new Object()); 
     } 
     return Flowable.error(throwable); 
    } 
    return Flowable.error(error); 
} 

但最大的問題有blockingGet()。我相信這是非常糟糕的解決方案。也許有人知道任何更好的?

0

也許你可以使用retryWhen

返回一個可觀察到發射相同的值作爲源ObservableSource與onError異常。源代碼中的onError通知將導致向Threatable項發出ObservableSource,作爲notificationHandler函數的參數提供。如果該ObservableSource調用onComplete或onError,則重試將在子訂閱上調用onComplete或onError。否則,這個ObservableSource將重新訂閱源ObservableSource。

Completable getAndStoreUserData = loginManager.getAccessToken() 
      .flatMap(loginManager::downloadUserAccountData) 
    .retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() { 
       @Override 
       public ObservableSource<?> apply(@io.reactivex.annotations.NonNull Observable<Throwable> throwableObservable) throws Exception { 

        return throwableObservable.map(new Function<Throwable, ObservableSource<?>>() { 
         @Override 
         public ObservableSource<?> apply(@io.reactivex.annotations.NonNull Throwable throwable) throws Exception { 
          if (throwable.getMessage().contains("403")){ // dummy test example 
           return loginManager.getRefreshToken() 
             .flatMap(loginManager::refreshAccessToken) 
             .flatMap(loginManager::downloadUserAccountData) 
          } 
          return whatever; 
         } 
        }); 
       } 
      }) 
    .flatMap(userManager::parseUserJson) 
    .flatMapCompletable(userManager::storeUser); 

Here一些其它示例。

對不起,我的英語和我不熟悉拉姆達。

+0

)你能提供一個簡單的例子,即使在字符串上操作,代表我的問題嗎?目前我不知道如何使用它。 –

+0

是的,我會嘗試。 – Cochi