2015-05-15 34 views
26

我想要一個接一個地執行2個網絡調用。這兩個網絡調用都返回Observable。第二次呼叫使用來自第一次呼叫成功結果的數據,第二次呼叫成功結果的方法使用來自的數據,第一次和第二次呼叫的成功結果均爲。另外,我應該能夠以不同方式處理兩個 onError「事件」。我怎樣才能做到這一點,避免回調地獄像下面的例子中:連鎖兩個改造的可觀察性w/RxJava

 API().auth(email, password) 
      .subscribeOn(Schedulers.newThread()) 
      .observeOn(AndroidSchedulers.mainThread()) 
      .subscribe(new Action1<AuthResponse>() { 
       @Override 
       public void call(final AuthResponse authResponse) { 
        API().getUser(authResponse.getAccessToken()) 
          .subscribe(new Action1<List<User>>() { 
           @Override 
           public void call(List<User> users) { 
            doSomething(authResponse, users); 
           } 
          }, new Action1<Throwable>() { 
           @Override 
           public void call(Throwable throwable) { 
            onErrorGetUser(); 
           } 
          }); 
       } 
      }, new Action1<Throwable>() { 
       @Override 
       public void call(Throwable throwable) { 
        onErrorAuth(); 
       } 
      }); 

我知道的拉鍊,但我想避免打造「合班」。

更新1 試圖執行akarnokd的回答是:

  API() 
      .auth(email, password) 
      .subscribeOn(Schedulers.newThread()) 
      .observeOn(AndroidSchedulers.mainThread()) 
      .flatMap(authResponse -> API() 
        .getUser(authResponse.getAccessToken()) 
        .doOnError(throwable -> { 
         getView().setError(processFail(throwable)); 
        }), ((authResponse, users) -> { 
       // Ensure returned user is the which was authenticated 
       if (authResponse.getUserId().equals(users.get(0).getId())) { 
        SessionManager.getInstance().initSession(email, password, authResponse.getAccessToken(), users.get(0)); 
        getView().toNews(); 
       } else { 
        getView().setError(R.string.something_went_wrong); 
       } 
      })); 

但是裏面flatMap方法編譯器說,它無法解析authResponse和用戶(authResponse.getAccessToken()users.get(0)等)的方法。我是新的rx編程和lambda - 請告訴我有什麼問題。無論如何,代碼看起來更清潔。

更新2

API() 
      .auth(email, password) 
      .subscribeOn(Schedulers.newThread()) 
      .observeOn(AndroidSchedulers.mainThread()) 
      .doOnError(throwable -> getView().setError(processFail(throwable))) 
      .flatMap((AuthResponse authResponse) -> API() 
        .getUser(authResponse.getAccessToken()) 
        .doOnError(throwable -> getView().setError(processFail(throwable))), ((AuthResponse authResponse, List<User> users) -> { 
          // Ensure returned user is the which was authenticated 
          if (authResponse.getUserId().equals(users.get(0).getId())) { 
           SessionManager.getInstance().initSession(email, password, authResponse.getAccessToken(), users.get(0)); 
           getView().toNews(); 
          } 
          return Observable.just(this); 
      })); 

都做到了這樣,但現在我的網絡電話無法執行的。

+0

我從IDE了,但我認爲錯誤是由於拉姆達參數名稱衝突。 – akarnokd

+1

看起來你不再訂閱了。確保你在鏈的底部調用.subscribe()。 –

回答

10

除了Anthony R.的答案,還有一個flatMap超載,它需要一個Func2並將您的主要值和展平值與您配對。另外,看看onErrorXXX和錯誤操作onExceptionXXX運營商,並與您的第一和第二觀測量把它們連

first.onErrorReturn(1) 
.flatMap(v -> service(v).onErrorReturn(2), (a, b) -> a + b); 
+0

謝謝,我會試試這個。使用Retrolambda for Android有什麼限制嗎? – localhost

+0

是的,我的例子是使用flatMap()的重載。 onErrorReturn可以工作,只是返回null,但然後flatMap()中的func必須在返回第二個Observable之前進行空檢查,我想。我不確定這些問題中的哪一個比問題中的原始代碼更清晰。 –

+0

在Android上使用retrolambda的限制記錄在這裏:https://github.com/evant/gradle-retrolambda#known-issues –

15

你看過flatMap()嗎?如果你厭惡它(或zip())是需要製造一個不必要的類來容納兩個對象,android.util.Pair可能是一個答案。不過,我不確定如何獲得您正在尋找的錯誤處理。

 API().auth(email, password) 
     .subscribeOn(Schedulers.newThread()) 
     .observeOn(AndroidSchedulers.mainThread()) 
     .flatMap(new Func1<AuthResponse, Observable<List<User>>>() { 
      @Override 
      public Observable<List<User>> call(AuthResponse authResponse) { 
      return API().getUser(authResponse.getAccessToken()); 
      } 
     }, new Func2<AuthResponse, List<User>, Pair<AuthResponse, List<User>>>() { 
      @Override 
      public Pair<AuthResponse, List<User>> call(AuthResponse authResponse, List<User> users) { 
      return new Pair<>(authResponse, users); 
      } 
     }).subscribe(new Action1<Pair<AuthResponse, List<User>>>() { 
      @Override 
      public void call(Pair<AuthResponse, List<User>> pair) { 
      doSomething(pair.first, pair.second); 
      } 
     }, new Action1<Throwable>() { 
      @Override 
      public void call(Throwable throwable) { 
      // not sure how to tell which one threw the error 
      } 
     }); 
+0

你能給我一個flatmap的例子嗎?對於Pair,如果它超過2個對象呢? – localhost

+0

你可以使用使用Func1到Func9,還有一個FuncN。 – Aegis

+0

在這種情況下,'API()。getUser(..)'調用將不會在後臺線程中運行嗎? – clu