In the SplashActivity
of my Android Application, the following sequence of events occur:
- Check if Google Play Services is installed
- If Google Play Services are available, start the
InstanceIDListener
service - Check if app needs to be updated
- Load country info using network IP
Previously, I'd implemented this logic using listeners but I decided to switch to RxJava/RxAndroid so that the sequence of events could be implemented more cleanly.
I'm very new to the whole Reactive Programming thing so I'd appreciate it if someone would go through my implementation below and tell me how I can improve it.
SplashActivity.java
public class SplashActivity extends BaseActivity {
private Subscription mSubscription;
@
Override
protected boolean showToolbar() {
return false;
}
@
Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
mSubscription = Observable.just(GooglePlayServicesInstallation.verify(this, 100))
.flatMap(new Func1 < GooglePlayServicesInstallation, Observable < Void >> () {@
Override
public Observable < Void > call(GooglePlayServicesInstallation installation) {
return handleInstallationStatus(installation);
}
}).flatMap(new Func1 < Object, Observable < Void >> () {@
Override
public Observable < Void > call(Object o) {
startGCMTokenService();
return Observable.just(null);
}
}).flatMap(new Func1 < Object, Observable < AppStatus >> () {@
Override
public Observable < AppStatus > call(Object o) {
return AppStatusAssistant.checkAppVersion(SplashActivity.this);
}
}).flatMap(new Func1 < AppStatus, Observable < Void >> () {@
Override
public Observable < Void > call(AppStatus appStatus) {
return handleAppStatus(appStatus);
}
}).flatMap(new Func1 < Void, Observable < Void >> () {@
Override
public Observable < Void > call(Void aVoid) {
return getApp().loadCountryInfo();
}
}).flatMap(new Func1 < Void, Observable < Void >> () {@
Override
public Observable < Void > call(Void aVoid) {
onInitializationComplete();
return Observable.just(null);
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe();
}
@
Override
protected void onStop() {
super.onStop();
if (mSubscription != null && !mSubscription.isUnsubscribed()) {
mSubscription.unsubscribe();
}
}
private Observable < Void > handleInstallationStatus(GooglePlayServicesInstallation googlePlayServices) {
if (googlePlayServices.isInstalled()) {
return Observable.just(null);
}
if (googlePlayServices.isNotInstalledRecoverable()) {
googlePlayServices.getDialog().show();
} else if (googlePlayServices.isNotInstalledIrrecoverable()) {
showMessageDialog("app can not run on this device because it does not support Google Play Services");
}
return Observable.empty();
}
private void startGCMTokenService() {
Intent intent = new Intent(SplashActivity.this, MyInstanceIDListenerService.class);
SplashActivity.this.startService(intent);
}
private Observable < Void > handleAppStatus(AppStatus status) {
if (status == null) {
return Observable.just(null);
}
mAppUpdateRequired = status.isEnforced() || status.isRecommended();
return mAppUpdateRequired ? showUpdateAppDialog(status.isEnforced()) : Observable. < Void > just(null);
}
private Observable < Void > showUpdateAppDialog(final boolean enforced) {
return Observable.create(new Observable.OnSubscribe < Void > () {@
Override
public void call(final Subscriber < ? super Void > subscriber) {
runOnUiThread(new Runnable() {@
Override
public void run() {
AlertDialog.Builder builder = new AlertDialog.Builder(SplashActivity.this);
builder.setCancelable(false)
.setTitle(R.string.update_available)
.setMessage(R.string.update_available_message)
.setPositiveButton(R.string.update_now, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
subscriber.onCompleted();
openAppInGooglePlay();
finish();
}
})
.setNegativeButton(R.string.later, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
if (enforced) {
subscriber.onCompleted();
finish();
} else {
mAppUpdateRequired = false;
subscriber.onNext(null);
}
}
});
AlertDialog alertDialog = builder.create();
try {
alertDialog.show();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
});
}
private void openAppInGooglePlay() {
Uri uri = Uri.parse("market://details?id=" + getPackageName());
Intent goToMarket = new Intent(Intent.ACTION_VIEW, uri);
try {
startActivity(goToMarket);
} catch (ActivityNotFoundException e) {
startActivity(new Intent(
Intent.ACTION_VIEW,
Uri.parse("http://play.google.com/store/apps/details?id=" + getPackageName())
));
}
}
private void onInitializationComplete() {
if (getApp().isUserSignedIn()) {
IntentUtils.startActivity(this, HomeActivity.class);
} else {
IntentUtils.startActivity(this, HomeRegisterActivity.class);
}
finish();
}
@
Override
protected void onNewIntent(Intent intent) {
this.setIntent(intent);
}
@
Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 100) {
IntentUtils.restartApp(this);
}
}
}
AppStatusAssistant.java
public class AppStatusAssistant {
public static Observable < AppStatus > checkAppVersion(@NonNull final BaseActivity activity) {
return activity.getWebApi().getAppStatus("android", getAppVersionCode(activity))
.flatMap(new Func1 < Response, Observable < AppStatus >> () {@
Override
public Observable < AppStatus > call(Response response) {
String responseString = APIUtils.responseToString(response);
if (TextUtils.isEmpty(responseString)) {
return Observable.just(null);
}
Gson gson = GsonUtils.getGson();
try {
JSONArray array = new JSONArray(responseString);
if (array.length() > 0) {
List < AppStatus > appStatuses = gson.fromJson(responseString, new TypeToken < List < AppStatus >> () {}.getType());
return Observable.just(appStatuses.get(0));
} else {
return Observable.just(null);
}
} catch (Exception ex) {
return Observable.just(null);
}
}
}).onErrorResumeNext(new Func1 < Throwable, Observable <? extends AppStatus >> () {@
Override
public Observable <? extends AppStatus > call(Throwable throwable) {
return Observable.just(null);
}
});
}
}
Note: I'm aware I should use Dagger to inject the API. That's another refactoring thing I'm working on.