Tutorial: How to use a foreground service

Below we explain how to use a foreground service to fetch location updates when running in background. The foreground service uses Android's notification mechanism to notify the user on background activities. It also allows a user to interact with the service.

Note

A full implementation can be seen in the PositioningWithBackgroundUpdates example app you can find on GitHub.

Step 1: Create a subclass of Service

Extend the Service class and override the necessary methods. In this tutorial we called the class ForegroundService - a full implementation of this class can be found on GitHub.

public class ForegroundService extends Service {
    private static final String CHANNEL_ID = "ForegroundServiceChannel";

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        String input = intent.getStringExtra("inputExtra");
        createNotificationChannel();
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,
                0, notificationIntent, 0);

        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle("Foreground Service")
                .setContentText(input)
                .setSmallIcon(R.drawable.ic_stat_name)
                .setContentIntent(pendingIntent)
                .build();

        startForeground(1, notification);

        // Here is a good place to handle the location consent.        
        // You can already start the LocationEngine here.

        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        // Here is a good place to stop the LocationEngine.
        super.onDestroy();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        // Here we do not use a binder to interact with the foreground service.
        return null;
    }
}

Step 2: Create a notification channel

For creating a notification channel, add the below code to our ForegroundService class:

private void createNotificationChannel() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel serviceChannel = new NotificationChannel(
                CHANNEL_ID,
                "Foreground Service Channel",
                NotificationManager.IMPORTANCE_DEFAULT
        );

        NotificationManager manager = getSystemService(NotificationManager.class);
        manager.createNotificationChannel(serviceChannel);
    }
}

Step 3: Insert location handling

In order to handle the user's consent, more code needs to be injected as shown on GitHub or in the Find Your Location section. This part is always required - even if you do not want to enable background updates.

Also, you definitely want to implement methods such as startLocating() to receive location updates and stopLocating() when an app gets disposed. These methods are always required - even if you do not want to enable background updates. The code can be found on GitHub or in the Find Your Location section.

Similarly, you need to implement a LocationListener to handle location updates. For this you can use the same code as for non-background updates.

Step 4: Start the foreground service from your Activity

In order to enable getting background updates, call startService(). The service can be stopped by calling stopService(), for example via dedicated buttons. The following two methods can be added to your Activity:

public void startService() {
    Intent serviceIntent = new Intent(this, ForegroundService.class);
    serviceIntent.putExtra("inputExtra", "Foreground Service Example in Android");
    ContextCompat.startForegroundService(this, serviceIntent);
}

public void stopService() {
    Intent serviceIntent = new Intent(this, ForegroundService.class);
    stopService(serviceIntent);
}

Step 5: Declare the service and add permissions

In the AndroidManifest you need to add the name of your Service class and type of foreground service.

Note we also need to explicitly ask the user to allow background updates by adding the ACCESS_BACKGROUND_LOCATION permission. In addition, we need the FOREGROUND_SERVICE and the POST_NOTIFICATIONS permissions.

Below you can find an example, together with all other permissions that are required by HERE Positioning:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.foregroundservice">

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <service
            android:name=".ForegroundService"
            android:enabled="true"
            android:exported="true"
            android:foregroundServiceType="location" />

        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

That's it - now your app will be fully operable in background and can receive location events - even if the device is locked. Note that handling of location updates in background can be a sensitive topic, so make sure to inform your users why you need this feature - and be aware that the Android OS will notify the user on the lock screen that your app is running and active. Consider to use less frequent location updates to avoid draining the battery when not necessary, for example, by setting a less-frequent LocationAccuracy, like for example, HUNDREDS_OF_METERS.

results matching ""

    No results matching ""