Android Foreground Service Example


Android Foreground Service

Android guidelines suggest that a long running operation should be performed in a service. As that long running operation may not require a UI and Android Services do not provide a UI. But what if that long running operation requires a UI or maybe just two or three pre-defined inputs. The first solution that comes in my mind is Android Foreground Service. This type of service falls under the category of started service, as its not bound to any component and neither it returns any result back to the caller.

Introduction to Android Foreground Service

Lets start with a basic know hows; As you may know that services are used for time consuming operations which do not require a user interface. But there are situations when long running operations are in progress and you would want the user to know progress of that operation. E.g.:

  1. Music Player
  2. VOIP Calls
  3. File Download
  4. and many more

Services have a unique property; once ‘started’ they can run even if you put the app in background. All the above listed operations are similar sort of operations, once started they don’t need a UI to complete. But for good user experience you would want the user to know that, this sort of operation is going on. Also now notifications in android allow for three action buttons, through which the user can interact with the ongoing operation if they want. Therefore the best suitable approach for these sort of operations is an Android Foreground Service.

In this tutorial for Android foreground service, I would make a music player stub (not an actual player). Here the user would be able to start a foreground service from an activity by calling startService() method. After this when  onStartCommand() method is invoked in service class, I would call the actual startForeground() method. By doing this Android would fire a notification, and from now on this service would be called as an Android Foreground Service. The interesting part here would be that after starting the service we can actually close the activity and interact with service through the notification buttons, or notification actions. To start off lets have a look at the App Manifest:

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

    <uses-sdk
        android:minSdkVersion="11"
        android:targetSdkVersion="19" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:launchMode="singleTask" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service android:name=".ForegroundService" >
        </service>
    </application>

</manifest>

Point to be noted here is that the main activity is launched in android:launchMode="singleTask", as whenever we launch this activity we want only once instance of it at task root level. In this Android Foreground Service Example I have used a constants file to keep the code clean. In any project, as a good coding practice it is advised that all constants are kept in a single class, as its a little easier to access. Have a look at the constants file for this example:

package com.truiton.foregroundservice;

public class Constants {
	public interface ACTION {
		public static String MAIN_ACTION = "com.truiton.foregroundservice.action.main";
		public static String PREV_ACTION = "com.truiton.foregroundservice.action.prev";
		public static String PLAY_ACTION = "com.truiton.foregroundservice.action.play";
		public static String NEXT_ACTION = "com.truiton.foregroundservice.action.next";
		public static String STARTFOREGROUND_ACTION = "com.truiton.foregroundservice.action.startforeground";
		public static String STOPFOREGROUND_ACTION = "com.truiton.foregroundservice.action.stopforeground";
	}

	public interface NOTIFICATION_ID {
		public static int FOREGROUND_SERVICE = 101;
	}
}

Next lets define the layout for main activity:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="52dp"
        android:text="Main Screen"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/textView1"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="26dp"
        android:text="Start Foreground Service" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/button1"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="35dp"
        android:text="Stop Foreground Service" />

</RelativeLayout>

After defining layout it would look something like this:

Android Foreground Service

Let me define the MainActivity.java, from where I’ll start the service:

package com.truiton.foregroundservice;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends AppCompatActivity implements OnClickListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button startButton = (Button) findViewById(R.id.button1);
        Button stopButton = (Button) findViewById(R.id.button2);

        startButton.setOnClickListener(this);
        stopButton.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button1:
                Intent startIntent = new Intent(MainActivity.this, ForegroundService.class);
                startIntent.setAction(Constants.ACTION.STARTFOREGROUND_ACTION);
                startService(startIntent);
                break;
            case R.id.button2:
                Intent stopIntent = new Intent(MainActivity.this, ForegroundService.class);
                stopIntent.setAction(Constants.ACTION.STOPFOREGROUND_ACTION);
                startService(stopIntent);
                break;

            default:
                break;
        }

    }
}

As you can see in the above piece of code, I have defined the objects for two buttons and on click of first button I am starting the service in foreground mode, and on click of second button I have written the code to stop the service. Now lets define the main class of this Android Foreground Service Example, ForegroundService.java:

package com.truiton.foregroundservice;

import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

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

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

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		if (intent.getAction().equals(Constants.ACTION.STARTFOREGROUND_ACTION)) {
			Log.i(LOG_TAG, "Received Start Foreground Intent ");
			Intent notificationIntent = new Intent(this, MainActivity.class);
			notificationIntent.setAction(Constants.ACTION.MAIN_ACTION);
			notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
					| Intent.FLAG_ACTIVITY_CLEAR_TASK);
			PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
					notificationIntent, 0);

			Intent previousIntent = new Intent(this, ForegroundService.class);
			previousIntent.setAction(Constants.ACTION.PREV_ACTION);
			PendingIntent ppreviousIntent = PendingIntent.getService(this, 0,
					previousIntent, 0);

			Intent playIntent = new Intent(this, ForegroundService.class);
			playIntent.setAction(Constants.ACTION.PLAY_ACTION);
			PendingIntent pplayIntent = PendingIntent.getService(this, 0,
					playIntent, 0);

			Intent nextIntent = new Intent(this, ForegroundService.class);
			nextIntent.setAction(Constants.ACTION.NEXT_ACTION);
			PendingIntent pnextIntent = PendingIntent.getService(this, 0,
					nextIntent, 0);

			Bitmap icon = BitmapFactory.decodeResource(getResources(),
					R.drawable.truiton_short);

			Notification notification = new NotificationCompat.Builder(this)
					.setContentTitle("Truiton Music Player")
					.setTicker("Truiton Music Player")
					.setContentText("My Music")
					.setSmallIcon(R.drawable.ic_launcher)
					.setLargeIcon(
							Bitmap.createScaledBitmap(icon, 128, 128, false))
					.setContentIntent(pendingIntent)
					.setOngoing(true)
					.addAction(android.R.drawable.ic_media_previous,
							"Previous", ppreviousIntent)
					.addAction(android.R.drawable.ic_media_play, "Play",
							pplayIntent)
					.addAction(android.R.drawable.ic_media_next, "Next",
							pnextIntent).build();
			startForeground(Constants.NOTIFICATION_ID.FOREGROUND_SERVICE,
					notification);
		} else if (intent.getAction().equals(Constants.ACTION.PREV_ACTION)) {
			Log.i(LOG_TAG, "Clicked Previous");
		} else if (intent.getAction().equals(Constants.ACTION.PLAY_ACTION)) {
			Log.i(LOG_TAG, "Clicked Play");
		} else if (intent.getAction().equals(Constants.ACTION.NEXT_ACTION)) {
			Log.i(LOG_TAG, "Clicked Next");
		} else if (intent.getAction().equals(
				Constants.ACTION.STOPFOREGROUND_ACTION)) {
			Log.i(LOG_TAG, "Received Stop Foreground Intent");
			stopForeground(true);
			stopSelf();
		}
		return START_STICKY;
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		Log.i(LOG_TAG, "In onDestroy");
	}

	@Override
	public IBinder onBind(Intent intent) {
		// Used only in case of bound services.
		return null;
	}
}

Please Note: R.drawable.truiton_short is just an image I used for displaying the notification large icon in setLargeIcon method, you can use any other drawable or bitmap like R.drawable.ic_launcher.

In the above class, as you can see I am starting the foreground service by calling startForeground() method. This is the point when a normal service transforms into a foreground service. Also please keep in mind that when a foreground service is stopped by calling the  stopForeground() method it does not stop the service, it just removes the service from foreground mode. To stop the service you may have to call the  stopSelf() method. To start a service in foreground mode, you need to create an Android notification with notification id. So lets have a closer look at the notifications:

Android Notification with Button

In this Android Foreground Service Example a special type of notification is used. This type of notification can perform actions, and they are called Android notification actions. Please have a look at the screen shot below:

Android Foreground Service - Android Notification with buttons

For a better understanding also have a look at the full source code:

Full Source Code

You may observe that, above notification has three buttons/actions attached to it. To do this, one has to use the addAction method, with appropriate pending intent. If you closely observe the above class, getService method is used for pendingIntents of notification actions. By using this method my intent would go directly to the onStartCommand() method of my ForegroundService. This would deliver my intent directly to the service instead of going through an activity. The advantage of this approach is that, I don’t need to be dependent on my activity. This truly makes this service a foreground service. Hope this Android Foreground Service Example helped.

About Mohit Gupt

An android enthusiast, and an iPhone user with a keen interest in development of innovative applications.


Leave a comment

Your email address will not be published. Required fields are marked *

16 thoughts on “Android Foreground Service Example