Сделайте что-нибудь после успешного входа в систему, используя RxJava и Retrofit 2

Я реализовал сетевой вызов для проверки входа в систему, который работает нормально. Я просто столкнулся с проблемой при выполнении другого вызова для получения данных пользователя после успешного входа в систему.

Вот вызов API:

RestApi restApi = ServiceRest.createRetrofitService(RestApi.class, UrlServer.URL_SERVER);
Observable<Response<User>> responseObservable = restApi.getUser(user);
responseObservable.subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .unsubscribeOn(Schedulers.io())
        .subscribe(new Subscriber<Response<User>>() {
            @Override
            public void onCompleted() {
                Log.i("LoginActivity", "[onCompleted]");
                progressDialog.dismiss();
            }

            @Override
            public void onError(Throwable e) {
                progressDialog.dismiss();
                Toast.makeText(LoginActivity.this, "Error: " + e.getMessage(), Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onNext(Response<User> userResponse) {
                //Do stuff to go to another Activity
            }
        });


------------- Редактировать №1 -------------

Я реализовал то, что предложил @Tassos, следующим образом:

responseUser
         .subscribeOn(Schedulers.io())
         .observeOn(AndroidSchedulers.mainThread())
         .map(new Func1<Response<User>, Observable<Response<Object>>>() {
                 @Override
                 public Observable<Response<Object>> call(Response<User> userResponse) {
                     Log.d("USER", userResponse.body().getName());
                     return restApi.getData(userResponse.body().getToken());
                 }
            })
            .doOnError(new Action1<Throwable>() {
                @Override
                public void call(Throwable throwable) {
                    Toast.makeText(LoginActivity.this, "Error[doOnError]: " + throwable.toString(), Toast.LENGTH_SHORT).show();
                }
            })
            .subscribe(new Subscriber<Object>() {
                @Override
                public void onCompleted() {
                    Log.i("LoginActivity", "[onCompleted]");
                }
                @Override
                public void onError(Throwable e) {
                    Toast.makeText(LoginActivity.this, "Error: " + e.getMessage(), Toast.LENGTH_SHORT).show();
                }
                @Override
                public void onNext(Object result) {
                    Log.d("RESPONSE", result.toString());
                }
            });

Правильно ли делать так в методе подписки? Нужно ли мне приводить результат объекта onNext?

//---------------------------------------------------------------------------- ------------------------------//

Я хочу после успешного входа в систему вызвать другой URL-адрес, используя токен, полученный через пользователя объекта Response, и отправить его на другой вызов API (Observable<Response<Object>> getData(@Header("Authorization") String token);) в качестве авторизации заголовка. Я пробовал использовать flatMap и zip, но не смог выполнить эту задачу.
Есть советы? Эта концепция для меня новая.


person Bruno Pardini    schedule 17.06.2016    source источник


Ответы (2)


Оператор .flatMap — идеальный способ сделать один вызов API, а затем другой. Читайте об этом здесь: http://blog.danlew.net/2014/09/22/grokking-rxjava-part-2/ часть «Будет еще лучше».

.flatMap позволяет заменить один observable на другой, т.е. сделать новый вызов API, используя результат предыдущего, реализуя цепочку событий. Если вы это сделаете, подписчик будет вызван для наблюдения, полученного от .flatMap.

Вы просто пишете:

restApi.getUser(user)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .flatMap(userResponse -> restApi.getData(userResponse.getToken()))
    .doOnError(e -> Toast.makeText(LoginActivity.this, "Error: " + e.getMessage(), Toast.LENGTH_SHORT).show())
    .doOnTerminate(() -> progressDialog.dismiss())
    .subscribe(response -> proceedWithLogin())

Кроме того, почему вы используете .unsubscribeOn(Schedulers.io())? Когда вы используете модифицированные наблюдаемые, они обычно генерируют одно событие, а затем завершаются, и нет необходимости настраивать планировщик отмены подписки.

person aleien    schedule 18.06.2016
comment
Я попробовал ваше решение, но оно возвращается java.net.SocketTimeoutException, а затем rx.exceptions.OnErrorNotImplementedException. Я реализовал doOnError - person Bruno Pardini; 20.06.2016
comment
Интересный. java.net.SocketTimeoutException вызвано getUser или getData? Вы можете попробовать сделать .subscribe(response -> proceedWithLogin(), throwable -> Log.d("Error", throwable.getMessage()), потому что OnErrorNotImplementedException означает, что для Observable не предусмотрена обработка ошибок. - person aleien; 20.06.2016
comment
Я предполагаю, что .doOnError просто вызывается, когда возвращается ответ об ошибке, но он не заменяет реализацию вызова onError подписчика. - person aleien; 20.06.2016
comment
Я должен подчеркнуть, что flatMap не возвращает элементы по порядку, если вычисление, стоящее за ним, является асинхронным. Если вы хотите сохранить порядок отображаемых наблюдаемых объектов, используйте concatMap. fernandocejas.com/2015/01/11/< /а> - person box; 25.10.2016

Вам действительно нужно, чтобы пользователь закрыл диалоговое окно? Вам обязательно нужно закрыть диалоговое окно перед выполнением других вызовов?

    .unsubscribeOn(Schedulers.io())
    .map(userResponse -> { /* do the other calls */ }
    .subscribe(new Subscriber<?>() {...
person Tassos Bassoukos    schedule 18.06.2016
comment
На самом деле я думал об этом, и мне не нужно закрывать диалоговое окно перед выполнением другого вызова... Мне нужно сохранить диалоговое окно и изменить сообщение с Проверка пользователя на Получение данных пользователя, и к концу последнего вызова диалог закрывается. Спасибо! Я столкнулся с проблемой, пытаясь реализовать то, что вы предложили, я отредактирую свой вопрос, чтобы показать, что я сделал. - person Bruno Pardini; 20.06.2016