Rxjava - цепочка наблюдаемых - PullRequest
0 голосов
/ 22 марта 2019

Пожалуйста, посмотрите на этот код:

 Disposable disposable = mcityService.authLogin(request,Utils.prepareHeaders())
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(resp ->
                {
                    mCompositeDisposable.add(mcityService.getUserDetails(selectedCity.id,Utils.prepareHeaders(resp.tokenType,resp.accessToken))
                            .subscribeOn(Schedulers.io())
                            .observeOn(AndroidSchedulers.mainThread())
                            .subscribe(userDetails ->
                            {
                                /*process resp and user details*/

                            }));


                }, throwable ->
                {
                    process errors
                });

        mCompositeDisposable.add(disposable);
    }

Так что в основном мне нужно позвонить authLogin, если это удастся, позвонить getUserDetails (требуются некоторые поля из authLogin результатов вызова), еслиgetUserDetails успешно выполнено, цепочка завершена, и мне нужны дополнительные результаты обработки обоих вызовов.Если authLogin терпит неудачу или getUserDetails терпит неудачу, должна выполняться обработка ошибок (например, получить код ошибки http или сообщение из throwable).

Поскольку мой подход работает, я знаю, что это не подход goot, какоптимизировать это?Могу ли я использовать оператор flatMap вместо вложенных наблюдаемых?

edit: объявления методов:

public static Map<String, String> prepareHeaders(String tokenType, String accessToken);
Observable<UserDetails> getUserDetails(@Path(value = "cityId", encoded = true) String cityId, @HeaderMap Map<String, String> headers);

Последняя попытка:

mcityService.authLogin(request, Utils.prepareHeaders())
                .concatMap(response ->
                {
                    final Map<String, String> headers = Utils.prepareHeaders(response.tokenType,response.accessToken);
                    return mcityService.getUserDetails(selectedCity.id, headers)
                            .map(userDetails -> new Object()
                            {
                                public AuthResponse ar = response;
                                public UserDetails ud = userDetails;
                            });
                })
                .doOnNext(responseDetails ->
                {
                   AuthResponse ar = responseDetails.ar;  
                   UserDetails ud = responseDetails.ud;   


                })
                .doOnError(throwable ->
                {

                    final String message = throwable.getMessage();

                });

Результаты: .doOnNext никогда не вызываетсяmcityService.getUserDetails, кажется, никогда не вызывается, .doOnError также никогда не вызывается (так что ошибки не было).Первый mcityService.authLogin звонок возвращается Observable<AuthResponse> разве мне не нужно subscribe?

1 Ответ

0 голосов
/ 22 марта 2019

Да, вы можете и должны использовать flatMap / concatMap / switchMap.
Кроме того, извините, если он не закодирован должным образом, я в основном использую RxJS, который имеет переносимые операторы (намного лучше!).

mcityService.authLogin(request, Utils.prepareHeaders())
            .concatMap(response -> { 
               final Map<String, String> headers = Utils.prepareHeaders(resp.tokenType,resp.accessToken);
               return mcityService.getUserDetails(selectedCity.id, headers)
                                  .map(userDetails -> ResponseUserDetails.of(response, userDetails));
            })
            .doOnNext(responseDetails -> {
               // Hanlde ResponseUserDetails object
            })
            .doOnError(throwable -> {
               // Handle exception
               final String message = throwable.getMessage();
               ...
            })
            .subscribe(
               responseDetails -> { ... },
               throwable -> { ... }
            );

Если вы не хотите использовать дополнительный класс, вы можете создать Object на лету

return mcityService.getUserDetails(selectedCity.id, headers)
                   .map(userDetails -> new Object() { 
                           public Response r = response;
                           public UserDetails ud = userDetails;
                   });

и получить доступ к его полям через

.doOnNext(responseDetails -> {
     final Response r = responseDetails.r;
     final UserDetails ud = responseDetails.ud;
     ...
})

static class ResponseUserDetails {
   final Response response;
   final UserDetails userDetails;

   ResponseUserDetails(
            final Response response,
            final UserDetails userDetails) {
      this.response = response;
      this.userDetails = userDetails;
   }

   static ResponseUserDetails of(
            final Response response,
            final UserDetails userDetails) {
      return new ResponseUserDetails(response, userDetails);
   }
}

enter image description here

...