Android Push Notifications — GCM and RxJava

Introduction

GCM seems to be a great case for utilising RxJava. Following the documentation for integrating GCM with Android an IntentService is created that handles the process of getting a GCM Token and sending it to a 3rd party server so Push Notifications can be sent.

Each of these steps requires the last in order to fully complete the sign up process to fully register a user for Push Notifications. This process can be thought of as a functional flow and therefore is a great fit for RxJava. It can benefit greatly from the use of RxJava’s Error Handling Operators operators in case of failure, such as Retry.

The rest of this post will assume you have some knowledge of GCM for Android and have read the documentation and already know the basics for RxJava.


Getting Started

You should have got an API key and Sender ID from Google. If you haven’t done this then do that before proceeding further.


Creating the IntentService

Firstly; create your GCM Registration IntentService class and register it in the Manifest. Oddly enough I called mine GcmRegistrationIntentService.

<service
android:name=".GcmRegistrationIntentService"
android:enabled="true" />

Make sure you override onHandleIntent as this is where we will setup the resources we will need and launch the registration process via RxJava.

I have a PushNotificationManager class to wrap the state I store in SharedPreferences and hold the GCM Token when the App receives it.

I have a GcmRequestManager class. The purpose of this class is to orchestrate network communication with the API that I send the GCM Token to. This uses Retrofit 2 (Beta), which already integrates RxJava and can return Observables. I am not going to go over how this works, but I will say that I return an Observable and any Exceptions thrown will be handled the same way as other examples.

Finally I have a reference to the GCM related class of InstanceID. This class is simply a requirement of the process, as it is an abstraction of the process of getting a GCM Token from Google.

Creating Observables from the GCM Methods

The classes provided by GCM do not utilise RxJava therefore we need to wrap them in such a way that they will emit an item when their task is complete.

The code above retrieves the GCM Token. Below you can see how wrapping it inside Observable.defer() lets us create an Observable that emits a String (the token) when the method completes.

The method getToken() can cause an IOException. So we can catch the exception as it occurs and then emit an Observable with an Error inside. One of the benefits of RxJava is that we can handle all the Exceptions in onError() of the Subscriber that we will setup next.

Similarly when subscribing to Topics we can follow a similar process.

Becomes

But why does it emit an Empty Observable?

This will be the last step in the process, we won’t be doing anything in OnNext() but we will be considering the process successfully complete when the onComplete() is called. If anything goes wrong then onError() will be called.

Create a Subscriber

We need to create a Subscriber to subscribe to getToken(). When getToken() completes it will call sendRegistrationToServer() which will then call registerTopics() via the use of the FlatMap() operator.

You might want to do things differently at this point, it depends on the final goal, however in this setup if any Exception is thrown then the whole process has to be completed again.

We could use extra flags to say what part of the process has been completed and resume from there, just as a simplistic way of taking this further.

Putting it all together…

The final step is to chain our observables together starting with getToken() that is called in onHandleIntent().

getToken().observeOn(Schedulers.io())
.flatMap(this::sendRegistrationToServer)
.subscribe(new GcmRegistrationSubscriber());

The above code will call sendRegistrationToServer() passing the received token in to the method. Note that

this::sendRegistrationToServer

equates to

() -> sendRegistrationToServer(token) )

It will use a new thread to do the work on via Schedulers.io() as we don’t want this long running on the main thread.

To link sendRegistrationToServer() to registerTopics() the flatMap() operator is used for the final time to call the registerTopics() method.

private Observable<Object> sendRegistrationToServer(String token) {

pushNotificationManager.setGcmPushToken(token);
return GcmRequestManager.getInstance(getApplicationContext())
.register()
.flatMap(this::registerTopics);
}

Final Code