Working with GCM Task Service on Android

The GCM Network Manager enables apps to register services that perform network-oriented tasks.
The API helps with scheduling these tasks, allowing Google Play services to batch network operations across the system.

Hence, multiple tasks get executed in a go, rather than executing each of them individually.
This in turns save battery as the mobile radio is awoken only once rather than waking up the device multiple times.

Using GCM Network Manager in our app

Add the dependency to build.gradle

dependencies {
    ...
    compile 'com.google.android.gms:play-services-gcm:8.4.0'
    ...
}

Next, declare a new Service in the Android Manifest which will make the network calls:

<service android:name=".GCMService"
        android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE"
        android:exported="true">
   <intent-filter>
       <action android:name="com.google.android.gms.gcm.ACTION_TASK_READY"/>
   </intent-filter>
</service>

The name of the service (GCMService) is the name of the class that will extend GcmTaskService, which is the core class for dealing with GCM Network Manager. This service will handle the running of a task.

Next we will define the GCMSerice class

public class GCMService extends GcmTaskService {
        ...
}

On implementing the methods from GcmTaskService, we have something like this :

@Override
public int onRunTask(TaskParams taskParams) {
        switch (taskParams.getTag()) {
                case TAG_TASK_ONEOFF_LOG:
                        //bundle with other tasks and then execute
                        return GcmNetworkManager.RESULT_SUCCESS;
                case TAG_TASK_PERIODIC_LOG:
                        //run this periodically 
                        return GcmNetworkManager.RESULT_SUCCESS;
                default:
                        return GcmNetworkManager.RESULT_FAILURE;
        }
}

Once this is set up, we need to schedule tasks from our Activity.

This can be done easily by first creating an object of GcmNetworkManager and class and hook up tasks to be executed from the above defined service

private GcmNetworkManager mGcmNetworkManager;

@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ...
        gcmNetworkManager = GcmNetworkManager.getInstance(this);
}

The GcmNetworkManager object will be used to schedule tasks, so one way to do this is to hold a reference as a member variable in onCreate . Alternatively, we can just get an instance of the GcmNetworkManager when we need it for scheduling.

Scheduling Tasks

Scheduling a OneOff Task

We provide the task with a window of execution, and the scheduler will determine the actual execution time. Since tasks are non-immediate, the scheduler can batch together several network calls to preserve battery life.

The scheduler will consider network availability, network activity and network load. If none of these matter, the scheduler will always wait until the end of the specified window.

Now, here’s how we would schedule a one-off task:

Task task = new OneoffTask.Builder()
              .setService(GCMService.class)
              .setExecutionWindow(0, 30)
              .setTag(LogService.TAG_TASK_ONEOFF_LOG)
              .setUpdateCurrent(false)
              .setRequiredNetwork(Task.NETWORK_STATE_CONNECTED)
              .setRequiresCharging(false)
              .build();

mGcmNetworkManager.schedule(task);

Using the builder pattern, we define all the aspects of our Task:

  • Service: The specific GcmTaskService that will control the task. This will allow us to cancel it later.
  • Execution window: The time period in which the task will execute. First param is the lower bound and the second is the upper bound (both are in seconds).
  • Tag: We’ll use the tag to identify in the onRunTask method which task is currently being run. Each tag should be unique, and the max length is 100.
  • Update Current: This determines whether this task should override any pre-existing tasks with the same tag. By default, this is false.
  • Required Network: Sets a specific network state to run on. If that network state is unavailable, then the task won’t be executed until it becomes available.
  • Requires Charging: Whether the task requires the device to be connected to power in order to execute.

All together, the task is built, scheduled on the GcmNetworkManager instance, and then eventually runs when the time is right.

Scheduling a periodic task

Here’s what a periodic task looks like:

Task task = new PeriodicTask.Builder()
                        .setService(GCMService.class)
                        .setPeriod(30)
                        .setFlex(10)
                        .setTag(LogService.TAG_TASK_PERIODIC_LOG)
                        .setPersisted(true)
                        .build();

mGcmNetworkManager.schedule(task);

It seems pretty similar, but there are a few key differences:

  • Period: Specifies that the task should recur once every interval at most, where the interval is the input param in seconds.
  • Flex: Specifies how close to the end of the period (set above) the task may execute. With a period of 30 seconds and a flex of 10, the scheduler will execute the task between the 20-30 second range.
  • Persisted: Determines whether the task should be persisted across reboots. Defaults to true for periodic tasks, and is not supported for one-off tasks. Requires “Receive Boot Completed” permission, or the setter will be ignored.

Cancelling Tasks

We saw how to schedule tasks, so now we should also take a look at how to cancel them. There’s no way to cancel a task that is currently being executed, but we can cancel any task that hasn’t yet run.

We can cancel all tasks for a given GcmTaskService:

  • gcmNetworkManager.cancelAllTasks(GCMService.class);

    And we can also cancel a specific task by providing its tag and GcmTaskService:

    gcmNetworkManager.cancelTask(
            GCMService.TAG_TASK_PERIODIC_LOG,
            GCMService.class
    );

    Well, we took a deep look at the GCM Network Manager and how to use it to conserve battery life, optimize network performance, and perform batched work using Tasks.
    I would urge you to try this out in your app for a streamlined yet robust approach on making networking calls.

the-dagger

Android Developer, Open Source Enthusiast