I am just starting to learn about RxJava and have been having some struggles with it lately. I have a section of code that needs to be done using RxJava and I don't want the rest of my code to be ran until either onSuccess()
or onError()
of my observer are called. My current implementation is as follows:
@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;
}
}
Is there any way that I can prevent the rest of my code from running until my observer completes its subscription?
To provide some better context on this, what I'm trying to implement is a custom account authenticator for Android. When the user first logs in, they won't have an auth token, so I obtain a new one using RxJava (as shown above). Then, I need to return a Bundle
back to the Android AccountManager
, which depends on whether I was able to successfully obtain the token or not.
I'm able to retrieve the access token using RxJava. However, if I try to read the token outside of the observer, the token is null because the request hasn't yet been completed... That's why I'm hoping to somehow pause the execution of the rest of the code until the subscription is complete.
As always, any assistance on this particular issue would be greatly appreciated :)
If this is your Single
Single<TokenResponse> singleResponse = client.getRxAccessToken(
encodedString,
LoginClient.GRANT_TYPE,
account.name,
password,
LoginClient.SCOPE
);
then try something like below (The return type of getAuthToken() needs to be changed):
@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());
}
Now create a method createBundle(TokenResponse tokenResponse)
like this
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);
}
}
);
}
Now who ever does subscribe on getAuthToken()
will get Bundle
getAuthToken()
.subscribe(
bundle -> //Use bundle as needed,
error -> //Handle error scenario
)
Hope this answer helps.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.