RxJava: приостановить выполнение кода до тех пор, пока элементы не будут отправлены - PullRequest
0 голосов
/ 04 декабря 2018

Я только начинаю узнавать о RxJava, и в последнее время у меня возникают некоторые проблемы с ним.У меня есть часть кода, которую необходимо выполнить с помощью RxJava, и я не хочу, чтобы остальная часть моего кода запускалась до тех пор, пока не будет вызван onSuccess() или onError() моего наблюдателя.Моя текущая реализация выглядит следующим образом:

    @Override
    public Bundle getAuthToken(AccountAuthenticatorResponse accountAuthenticatorResponse, Account account, String authTokenType, Bundle options) {
        final AccountManager manager = AccountManager.get(mContext);
        final String username = account.name;
        String token = manager.peekAuthToken(account, authTokenType);

        if (TextUtils.isEmpty(token)){
            final String password = manager.getPassword(account);
            if (password != null){
                LoginClient client = ClientGenerator.createClient(LoginClient.class);
                String encodedString = encodeClientIDAndSecret();

                // Current implementation of observer
                Single<TokenResponse> single = client.getRxAccessToken(encodedString, LoginClient.GRANT_TYPE, account.name, password, LoginClient.SCOPE);
                single.map(new Function<TokenResponse, String>() {
                    @Override
                    public String apply(TokenResponse tokenResponse) throws Exception {
                        return tokenResponse.getAccessToken();
                    }
                })
                        .subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(new DisposableSingleObserver<String>() {
                            @Override
                            public void onSuccess(String accessToken) {
                                Log.d(TAG, "Here is the access token: " + accessToken);
                            }

                            @Override
                            public void onError(Throwable e) {
                                Log.d(TAG, "Unsuccessful response...");
                            }
                        });

            }
        }

        token = manager.peekAuthToken(account, authTokenType);
        if (!TextUtils.isEmpty(token)){
            final Bundle result = new Bundle();
            result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
            result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
            result.putString(AccountManager.KEY_AUTHTOKEN, token);
            return result;
        } else {
            final Intent intent = new Intent(mContext, LoginActivity.class);
            intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, accountAuthenticatorResponse);
            intent.putExtra(LoginActivity.EXTRA_ACCOUNT_TYPE, account.type);
            intent.putExtra(LoginActivity.EXTRA_AUTH_TOKEN_TYPE, authTokenType);

            final Bundle bundle = new Bundle();
            bundle.putParcelable(AccountManager.KEY_INTENT, intent);
            return bundle;
        }
    }

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

Чтобы обеспечить лучший контекст дляэто то, что я пытаюсь реализовать, это собственный аутентификатор учетной записи для Android.Когда пользователь впервые входит в систему, у него не будет токена авторизации, поэтому я получаю новый, используя RxJava (как показано выше).Затем мне нужно вернуть Bundle обратно на Android AccountManager, что зависит от того, смог ли я успешно получить токен или нет.

Я могу получить токен доступа с помощью RxJava,Однако, если я попытаюсь прочитать токен за пределами наблюдателя, токен будет нулевым, потому что запрос еще не завершен ... Вот почему я надеюсь как-то приостановить выполнение остальной части кода до подпискизавершено.

Как всегда, любая помощь по этому конкретному вопросу будет принята с благодарностью:)

1 Ответ

0 голосов
/ 07 декабря 2018

Если это ваш Single

Single<TokenResponse> singleResponse = client.getRxAccessToken(
    encodedString,
    LoginClient.GRANT_TYPE,
    account.name,
    password,
    LoginClient.SCOPE
);

, попробуйте что-то вроде ниже (тип возврата getAuthToken () необходимо изменить):

@Override
public Single<Bundle> getAuthToken(AccountAuthenticatorResponse accountAuthenticatorResponse, Account account, String authTokenType, Bundle options) {
    Return singleResponse
        .flatMap(tokenResponse -> createBundle(tokenResponse))
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread());
}

Теперь создайте метод createBundle(TokenResponse tokenResponse) вот так

private Single<Bundle> createBundle(TokenResponse tokenResponse) {
    return Single.create(
        e -> {
            String token = tokenResponse.getAccessToken();
            manager.peekAuthToken(account, authTokenType);
            if (!TextUtils.isEmpty(token)){
                final Bundle result = new Bundle();
                result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
                result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
                result.putString(AccountManager.KEY_AUTHTOKEN, token);

                e.onSuccess(result);
            } else {
                final Intent intent = new Intent(mContext, LoginActivity.class);
                intent.putExtra(
                    AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, accountAuthenticatorResponse);
                intent.putExtra(LoginActivity.EXTRA_ACCOUNT_TYPE, account.type);
                intent.putExtra(LoginActivity.EXTRA_AUTH_TOKEN_TYPE, authTokenType);
                final Bundle bundle = new Bundle();
                bundle.putParcelable(AccountManager.KEY_INTENT, intent);

                e.onSuccess(bundle);
            }
        }
    );
}

Теперь тот, кто когда-либо подпишется на getAuthToken(), получит Bundle

getAuthToken()
    .subscribe(
        bundle -> //Use bundle as needed,
        error -> //Handle error scenario
    ) 

Надеюсь, этот ответ поможет.

...