Non killable background service in android

Android OS can kill your background service any time if it needs to free up the memory. But sometime developers need to keep it running for some task to be completed. So how do we do it? How do we ensure that service is keep running. Well, we can do it by using JobIntenetService and today we will learn how to. The idea is, even if the service gets killed it will be restarted. This tutorial is about implementing a non killable background service in android by JobIntenetService .

Create background service

Create a package in your project and name it services. In the service package create a Java class named BackgroundService. Make sure in your AndroidManifest.xml it is declared properly and it has the android.permission.BIND_JOB_SERVICE permission. Like below code:


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

    ...
    ...

    <application
        android:allowBackup="false"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Captaindroid"
        tools:targetApi="31">
        

        <service
            android:name=".services.BackgroundService"
            android:exported="false"
            android:permission="android.permission.BIND_JOB_SERVICE" />

        ...
        ...


    </application>

</manifest>

BackgroudService.java as JobIntentService

JobIntentService is very good choice for this kind of scenario. You can enqueue multiple tasks/works. Android OS will complete these tasks one by one and it make sure that the task gets completed. Even if the service gets killed, it will restarted.

Open your BackgroudService.java and extend JobIntentService. Implement all the methods. When you start the service and enqueue work don’t forget to publish a notification. Example is below:

public class BackgroundService extends JobIntentService {


    private NotificationManager mNotificationManager;
    private NotificationCompat.Builder mBuilder;


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


    public static void startWork(Context context){
        
        enqueueWork(
                context,
                BackgroundService.class,
                1,
                new Intent()
        );
        
    }


    @Override
    protected void onHandleWork(@NonNull Intent intent) {

        sendNotification("");
        startForeground(1, mBuilder.build());

        // your work goes here.
        // Implement your background location
        // or download file, etc
    }


    private void sendNotification(String fileName) {

        mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);

        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);

        mBuilder = new NotificationCompat.Builder(this)
                .setContentTitle("Title")
                .setStyle(new NotificationCompat.BigTextStyle()
                        .bigText(fileName))
                .setOngoing(true)
                .setContentText("Your content text")
                .setSmallIcon(R.mipmap.ic_launcher);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            CharSequence name = getString(R.string.app_name);
            String description = getString(R.string.app_name);
            int importance = NotificationManager.IMPORTANCE_HIGH;
            NotificationChannel channel = new NotificationChannel("1", name, importance);
            channel.setDescription(description);
            mNotificationManager.createNotificationChannel(channel);
            mBuilder.setChannelId("1");
        }

        mBuilder.setContentIntent(contentIntent);
        mBuilder.setOngoing(true);
        mBuilder.setOnlyAlertOnce(true);
        mNotificationManager.notify(1, mBuilder.build());

    }

}

Usage of BackgroudService.java

We are almost done. It’s time to use the service. Very easy. Just call BackgroudService’s startWork method like below:

BackgroundService.startWork(MainActivity.this);

startWork() method actually enqueues the work. When the work enqueues, immediately onHandleWork() is called by the OS. There you have to implement your logic and publish the notification. You see we are passing a new Intent() to enqueueWork method and receiving it in onHandleWork method. If you have to pass any data, you can put it in this intent and access it in onHandleWork.

And one more thing, you don’t have to wait for this task to be completed. You can call this method startWork() as many time as you needed. It will be enqueued and will be completed one by one.