Push, Don’t Poll – How to Use GCM to Update App Data

Written by: on September 26

There’s a big push for Android developers to stop polling servers for data and to adopt pushing techniques, using Google Cloud Messaging (GCM), to update your app’s data.

Pushing data has a number of benefits such as increased battery life and decreased server load. GCM is free to use and has no quotas, so it is a perfect candidate to handle the heavy lifting required for data updates.

There are two types of messages you can push with GCM: Send-to-sync and message with payload. A send-to-sync is basically a tickle, telling your app to sync with the server while a message with payload lets you send data in the push message (up to 4kb). Here’s a simple, full stack example that will help highlight how to get each of these types of push messages integrated with your app.

The app will take either a push message with a payload that updates the time that is saved on the device or a send to sync message that triggers the app to sync the time with the server. This was created using the “Generate App Engine Backend” feature of Android Studio. The Android developers blog has a tutorial on this. If you already have a backend setup, the GCM setup instructions for an existing server can be found here.

The source for this example is up on GitHub.

Create a new endpoint

Wizard generated files Message.java and MessageEndpoint.java in PushDontPoll-AppEngine were deleted, along with the messageendpoint package in PushDontPoll-endpoints. In lieu of this, DateEndpoint.java was created in PushDontPoll-AppEngine. This class makes an endpoint at /_ah/api/dateendpoint/v1/currentdate that provides the current time in JSON:

It also provides methods to send a message with payload and send to sync message via GCM. This was ripped out the deleted MessageEndpoint.java , so it only sends messages to a maximum of 10 devices. They are both built using GCM’s Message.Builder().

The message with payload adds the time to the data parameter. Key/value pairs added here will be automatically added as extras in the the intent bundle when parsing the message.

The send-to-sync message uses a collapse key so that only one message will be delivered if multiple tickles are queued up. You should not use more than four distinct keys since that is the maximum number that the GCM server can store. You can read more about this parameter here.

Add send-to-sync and payload message buttons

The index.html in the PushDontPoll-AppEngine project was modified to add buttons that allow us to send the two different types of push messages. Most of the wizard-generated code was removed for simplicity. The code to show the buttons is:

The functions that they call are:

These call the sendTickle() and sendUpdate() methods in DateEndpoint.java. Make sure you re-generate the client libraries after changing the PushDontPoll-AppEngine code (Tools -> Google Cloud Endpoints -> Generate Client Libraries).

Add code to parse GCM message

The wizard-generated files RegisterActivity.java and GCMIntentService.java were moved to the main project so they could use the Constants class. The added application code to show the saved time was added to the MainActivity class in order to keep things separated and easy to understand. The RegisterActivity is accessible via an action item.

Parsing the GCM message is done in the onMessage() method in the GCMIntentService class. This class is already fleshed out for you thanks to the wizard.

Parse send-to-sync

The send-to-sync message will have a collapse_key, so we can request a sync if that matches the sync type we’re expecting:

This uses a sync adapter with a stubbed authenticator and content provider – see here for more info. This can easily be modified to send a network request to sync using your method of choice (Volley, Retrofit, etc) if a sync adapter is not desirable. All of the syncing code is in the com.doubleencore.android.pushdontpoll.sync package, along with the necessary xml files in res/xml/ and in the AndroidManifest.xml.

In the onPerformSync() of the SyncAdapter, we can make a network request to the new endpoint that was created to get the current time:

Parse message with payload

The message with payload will have new_time as a key in the intent extras. This key coincides with the one we added when building the message. You can read more about the data parameter here.

In both cases, the time is then saved to shared preferences, and a local broadcast is sent to update the UI. Again, this can be done using your preferred method (event bus, observable cursor, etc).

Running the server

In order to use GCM, you must have an API key. You can enter this when running the wizard or by replacing it in DateEndpoint.java in the PushDontPoll-AppEngine project. The server can either be deployed as an App Engine app or run locally using the dev server.

Local instance

To run it as a local instance, you need to change:

Then you can just run the appengine:devserver maven goal, and it will be running on localhost. The server will now work with a Google API emulator.

If you want to access this local instance on a device (it must be on the same network as the local instance,) you’ll also need to change:

…and download the App Engine SDK from here, and run:

App Engine app

If you didn’t follow along in the blog and are just trying to get the sample code running, you need to create a Google Cloud Platform project and obtain the Project Number and Project ID. You can do this by following the Preliminary Setup section of this blog post.

Set the PROJECT_NUMBER variable in GCMIntentService.java to your project number and the <application> tag in appengine-web.xml to your project ID, and regenerate the client libraries.

You may also want to change the packages (com.doubleencore.android) and domains (doubleencore.com) to your domain.

Deploy the backend server by running the appengine:update maven goal. You can then access your server at http://<project-id>.appspot.com.

Running the Android app

You can now deploy the PushDontPoll app to your device or emulator. Once deployed, click on the GCM Register action item to register your device with the server. Once the success message appears, press back and navigate to your server on your computer. Pressing the “Send Tickle” button will push a message that signals the device to sync with the server. The device will hit the date endpoint for the current time, and the time should refresh on the device. Pressing the “Send Update” button will push a message that has the new time in the payload data. This should instantly update the time shown on the device without needing to make an additional trip to the server.

Hopefully, this simple example app will assist you in getting a push framework up and running for your app. I highly recommend reading through the GCM documentation to get a thorough understanding, as there are many features not discussed in this article. You will need to handle things, such as request spikes with send-to-sync messages, more gracefully than this sample does as well. Good luck and happy pushing!

Peter Elliott

Peter Elliott is a Software Engineer at Double Encore, specializing in Android Development.


Add your voice to the discussion: