TechPosts

Background Location Listener

Codename One now supports background location updates on selected platforms. This allows apps to be notified of significant location changes even when the app isn’t running.

How it works

There is a new build hint location.backgroundListener that allows you to specify a LocationListener implementation that should be used to monitor location changes when the app is in the background.

E.g. location.backgroundListener=com.mypackage.MyBackgroundLocationListener

Restrictions on the backgroundListener class:

  1. It must implement com.codename1.location.LocationListener

  2. It must have a no-arg public constructor.

When the app goes into the background, this listener will be set up to receive location updates periodically, without the app having to actively monitor the location.

Important
The background listener only runs while the app is in the background. It does not receive updates while the app is in the foreground.

Benefits of this Approach

It saves battery life while the app isn’t running since it isn’t actively monitoring GPS or keeping the device awake.

Down Sides of this Approach

You don’t have as much control over the precision or frequency of the location updates. On iOS, for example, this harnesses the significant location change service, which isn’t guaranteed to work to any particular precision.

The significant-change location service provides accuracy that’s good enough for most apps and represents a power-saving alternative to the standard location service. The service uses Wi-Fi to determine the user’s location and report changes in that location, allowing the system to manage power usage much more aggressively than it could otherwise. The significant-change location service can also wake up an iOS app that is currently suspended or not running in order to deliver new location data.
— Apple Developer Documentation

Example

The following example uses a background location listener to monitor when the location changes while the app is in the background. It then sends a local notification to alert the user to the location change:

The Listener class:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.codename1.demos.bgloc;

import com.codename1.location.Location;
import com.codename1.location.LocationListener;
import com.codename1.notifications.LocalNotification;
import com.codename1.ui.Display;

/**
 *
 * @author shannah
 */
public class BackgroundLocationMonitor  implements LocationListener {

    public void locationUpdated(Location location) {
        System.out.println("Background location updated "+location);

        LocalNotification n = new LocalNotification();
        n.setId("Some notification "+System.currentTimeMillis());
        n.setAlertBody("New Location "+location);
        n.setAlertTitle("Location updated");
        n.setBadgeNumber(2);
        n.setFireDate(System.currentTimeMillis());

        Display.getInstance().sendLocalNotification(n);


    }

    public void providerStateChanged(int newState) {
        System.out.println("Background provider state changed "+newState);

    }

}

Then we add the build hint:

location.backgroundListener=com.codename1.demos.bgloc.BackgroundLocationMonitor

One More Thing

We need to enable the background listener in our app by calling:

LocationManager.getLocationManager().startMonitoringBackgroundChanges();

Implementation Details

  1. If the location.backgroundListener directive is not present, then a background listener is never activated, and the LocationManager.isMonitoringBackgroundChangesSupported method must return false.

  2. If the location.backgroundListener directive is set and LocationManager.isMonitoringBackgroundChanges() returns true, then, upon the app entering the background:

    1. Any currently set LocationListener should be unset using LocationManager.setLocationListener(). It should be stored and later reinstated when the app enters the foreground.

    2. The background listener object should be set as the current location listener. BUT, if the platform has the ability to do background updates, this location manager should not be actively listening to the GPS directly. Instead it should register to only receive updates using the "efficient" background location mechanism of the platform - equivalent to iOS' significant location change service.

  3. If the a LocationListener was disabled upon entering the background, then it should be reinstated using LocationManager.setLocationListener(), and the background listener should cease to listen to any updates.