March 15th, 2016

Performing Background Data Refresh for Android

Pierce Boggan
Senior Program Manager

Data is a crucial component of any app, which is why perfecting how your application interacts with data is so important. There are many techniques for improving interactions with remote data, such as request prioritization, speculative requests, and caching. These are certainly techniques to be explored and used, but what if your data was there before users even opened your app?

Both iOS and Android expose mechanisms for refreshing data when your app is in the background (i.e. when a user is using a different app on their mobile device). Previously, we covered how to perform background data refresh on iOS. In this blog post, we’re going to walk through the process of adding background data refresh to Android apps with the Google Cloud Messaging service in just a few easy steps.

Introduction to Android Background Data Refresh

Google Cloud Messaging (GCM) provides a way to send data between a client and server. However, it also exposes some additional functionality that we can take advantage of (even if you aren’t using GCM as a data service for your apps), such as the ability to schedule recurring background data refreshes at a regular interval. To get started, add the Xamarin Google Play Services – GCM NuGet to your project.

Android provides a mechanism for performing operations in the background called a service. Google Cloud Messaging exposes a special type of service named GcmTaskService which we can use to configure how exactly the background refresh will take place. We can then use the GcmNetworkManager to schedule a task on a regular interval.

Creating a Background Service

Create a new subclass of GcmTaskService named BackgroundService. All services must be marked with the [Service] attribute so that they can properly be bundled into the AndroidManifest.xml file. You can also specify additional members, such as required permissions for the service to operate. IntentFilter can also be applied as an attribute to filter what types of messages the service responds to. Apply the following attributes to the BackgroundService class:

[Service (Exported = true, Permission = "com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE")]
[IntentFilter (new [] {"com.google.android.gms.gcm.ACTION_TASK_READY"})]

Next, override the OnRunTask method, where we’ll define the logic to refresh the app data in the background automatically. You should return either GcmNetworkManager.ResultSuccess GcmNetworkManager.ResultReschedule or GcmNetworkManager.ResultFailed, depending on the result of the background operation:

public override int OnRunTask (TaskParams @params)
{
    System.Threading.Tasks.Task.Run (async () => {
        // TODO: Perform background refresh logic here.
        Log.Debug ("Background Service", "Background Task Succeeded");
    });

    return GcmNetworkManager.ResultSuccess;
}

GcmTaskService is a type of bound service, so we must create a class that subclasses the Binder class, as seen below:

public class BackgroundServiceBinder : Binder
{
    BackgroundService service;

    public BackgroundServiceBinder (BackgroundService service)
    {
        this.service = service;
    }

    public BackgroundService GetBackgroundService ()
    {
        return service;
    }
}

The Binder class is responsible for maintaining a reference to our service so clients can make method calls against it. This is only created one time, in GcmTaskService‘s OnBind method and remains until it’s unbound. Override the OnBind method and initialize and return the binder:

IBinder binder;
public override IBinder OnBind (Intent intent)
{
    binder = new BackgroundServiceBinder (this);

    return binder;
}

Schedule the Background Data Refresh

Now that the GcmTaskService is properly configured, it’s time to schedule our task using the GcmNetworkManager. We can use the PeriodicTask</code builder to build a task around a set of options, including execution interval, the service to run, requiring a network connection, and more. Add a new method named StartBackgroundDataRefreshService to your MainActivity and call it from the OnCreate lifecycle method:

private void StartBackgroundDataRefreshService ()
{
    var pt = new PeriodicTask.Builder ()
        .SetPeriod (1800) // in seconds; minimum is 30 seconds
        .SetService (Java.Lang.Class.FromType (typeof(BackgroundService)))
        .SetRequiredNetwork (0)
        .SetTag ("com.pierceboggan.backgrounddatarefresh") // package name
        .Build ();

        GcmNetworkManager.GetInstance (this).Schedule (pt);
}

Configuration & Testing

Finally, GcmNetworkManager requires a Google App Id to function properly, even if your app is not using Google Cloud Messaging services. To do this, create a new app in the Google Developers Console. Copy the application identifier and create a new string entry in the Strings.xml file in the Resources/values directory:

APPLICATION_ID_HERE

Run the app, and you'll see it updates in the background every 30 seconds! For testing, ensure that the device (or emulator) in test has Google Play Services correctly installed, or GcmNetworkManager will not be able to properly operate.

Wrapping Up

In this blog post, we created a background data refresh service using the Google Cloud Messaging NuGet with GcmTaskService and scheduled our background service to run periodically using GcmNetworkManager. Adding background data refresh is super easy, and only requires a few lines of code to get up and running. For more information on background services, check out our documentation on Android services or our blog post on how to perform background refresh in iOS apps.

Author

Pierce Boggan
Senior Program Manager

Pierce is a Senior Program Manager on the Mobile Developer Tools team at Microsoft. He is responsible for IDE tooling for mobile developers in Visual Studio (Xamarin) and Visual Studio Code (React Native and Cordova). In his free time, Pierce enjoys playing ultimate, backpacking, and spending way too much time on side projects he will never finish.

0 comments

Discussion are closed.