Implementing GCM Network Manager for periodic network requests on Android
In the process of rebuilding What’s Shaking, NZ?, I needed to implement a periodic network request (literally polling an API). I wanted to use the new Job Scheduler API, but unfortunately, this is only available on API 21 and above. Luckily we can get similar functionality by using GCM Network Manager, as suggested on StackOverflow. Note that the GCM Network Manager actually uses Job Scheduler behind the scenes in API 21+.
The documentation for this is somewhat hand-wavy. Here I attempt to provide a true step-by-step guide to implementing this. I assume you’re not already using GCM for something else in your app (as that was the case for me).
Implement GcmTaskService
The first step is to import GCM in your build.gradle
:
1
|
|
Now you can implement GcmTaskService
. This is as simple as the following:
1 2 3 4 5 6 7 8 9 10 11 |
|
Great. So you get a callback, on a different thread, where you can do your stuff.
Add the service to the manifest
The instructions say to add the service to the manifest and “Add all applicable intent filters. See details for intent filter support in the GcmTaskService API reference.”
Note that the GcmTaskService documentation has SERVICE_ACTION_EXECUTE_TASK
as the name for the com.google.android.gms.gcm.ACTION_TASK_READY
intent filter. This is right now the only thing we need to care about.
We also need to add the RECEIVE_BOOT_COMPLETED
permission so that our periodic sync will persist across reboots.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Schedule a persistent task
You construct a PeriodicTask
object using a Builder
, and then pass that task to a GcmNetworkManager
instance - and that’s it! You can put this in your SyncService
class and call SyncService.scheduleSync(context)
:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
I’ve used the Once library to ensure that my periodic sync is scheduled once per app install (on first launch). I just call this method from my Application class onCreate
.
1 2 3 4 5 6 |
|
Re-schedule on app update
Finally, we need to ensure that our periodic task is re-scheduled after an app update by overriding the onInitializeTasks
method.
When your package is removed or updated, all of its network tasks are cleared by the GcmNetworkManager. You can override this method to reschedule them in the case of an updated package. This is not called when your application is first installed.
This is called on your application’s main thread.
This is trivial enough to do:
1 2 3 4 5 6 |
|
Test it
You can test that your background process works by firing off the intent that triggers it:
1 2 3 |
|
Note speakman.whatsshakingnz
is the package, and .network.SyncService
is the component name within that package. You need to specify the tag you used earlier, too. If you’ve got a debugger attached you can hit a breakpoint inside your onRunTask
method and note that you’re not on the main thread.
Gotchas
- you have to reschedule on app update - this is simple enough to do, make sure you remember to do it!
- check for Play Services! It’s required for this to work.
- if the network is unavailable/doesn’t meet the criteria you specified, you can’t force the task to trigger via ADB (useful to remember if you keep your test device in airplane mode!)
- use the tags to filter out different events in the same service -
taskParams.getTag()
returns the tag that the task was created with.