I am trying to chain network requests using RxJava in Android, and then retry when it fails. I've been looking over StackOverflow on how to do this without getting into Callback hell that comes with using vanilla Android and Retrofit alone. I can do this all in a procedure, in an asynchronous task like this (below are the steps that I need to make) to log in.
I've been doing this in an AsyncTask
which worked only when signing in. However, the SSO token expires while the application is in use, so I need to make the request every time I see that it expires.
The code for the AsyncTask looks like this:
private class LoginUserTask extends AsyncTask<Void, Void, Void> {
private final String LOG_TAG = LoginUserTask.class.getSimpleName();
@Override
protected Void doInBackground(Void... params) {
OkHttpClient httpClient = ((TribeSocial) getApplication()).getHttpClient();
// Login User
GroupDockService groupDockLoginService =
GroupDockServiceGenerator
.createService(GroupDockService.class,
httpClient, GroupDockUser.class, new GroupDockUserDeserializer());
GroupDockUser groupDockUser = groupDockLoginService.loginUser("Tribe", username, password);
Utility.saveAccountSubdomain(mContext, groupDockUser.getGroupDockSubdomain().getSubdomain());
// Get Sso Token
GroupDockService groupDockService = GroupDockServiceGenerator
.createService(GroupDockService.class, httpClient);
GroupDockSsoResponse ssoResponse =
groupDockService.getSsoToken(Utility.getAccountSubdomain(mContext), true);
Utility.saveSsoToken(mContext, ssoResponse.getSsoToken());
// Sign in user into Tribe service
TribeSocialService tribeSocialLaunchService =
TribeServiceGenerator.createService(TribeSocialService.class,
httpClient, new LenientGsonConverter(new Gson()));
tribeSocialLaunchService.launch(Utility.getSsoToken(mContext));
// Get User id and save it to SharedPreferences
TribeSocialService tribeSocialWhoAmIService =
TribeServiceGenerator.createService(TribeSocialService.class, httpClient,
User.class, new WhoAmIDeserializer());
User tribeUser = tribeSocialWhoAmIService.whoami();
Utility.saveUserId(mContext, tribeUser.getId());
return null;
}
@Override
protected void onPostExecute(Void v) {
Utility.launchMainActivity(mContext);
}
}
My attempt at making this work with RxJava is something like
GroupDockService groupDockLoginService =
GroupDockServiceGenerator
.createService(GroupDockService.class,
mHttpClient, GroupDockUser.class, new GroupDockUserDeserializer());
groupDockLoginService
.loginUserRx("Tribe", username, password)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<GroupDockUser>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
Log.e(LOG_TAG, "I have errored out: " + e.getMessage());
Toast.makeText(mContext,
getString(R.string.username_and_or_password_is_incorrect),
Toast.LENGTH_SHORT).show();
}
@Override
public void onNext(GroupDockUser groupDockUser) {
Utility.saveUsernamePassword(mContext, username, password);
new LoginUserTask().execute();
}
});
In that code, I need to do the following
The code right now simply makes a call to login the user, and once that succeeds, kicks off the async task. Ideally, I would like to chain the requests all together in that one request. I've been experimenting with flatmap
, map
, and etc., and can't figure out how to chain these calls as I stepped out above.
Can anyone shine some light on this? Thanks.
Take a look at this example. Hope, it will inspire you.
service
//do login
.loginUser()
//side effect: save into Shared Preference
.doOnNext( )
//get SSO
.flatMap()
//do any other side effects
.doOnNext()
//do final network request
.flatMap()
//in case of error retry after 5 seconds
.retryWhen(observable -> Observable.timer(5, TimeUnit.SECONDS))
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
//update you UI
.subscribe();
Further reading about retry
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With