Android JetPack WorkManager for background services

As we all know that Android Jetpack is the great feature given by Android Team. I have explained some of the awesome features of Jetpack like Navigation by NavigationUI and Paging Library for Jetpack.

What is WorkManager?

WorkManager is one of the Android Jetpack Articheture component libraries which is used to run the background services when the constraint is satisfied. As we all know that Google has now restricted to use the background service like Service or Intent Service into Doze Mode. If you want to run the service, then it should be run into the foreground.

While for periodic or schedule background service is always holding the resource like AlarmManager, which consume a lot of memory space. In this case, WorkManager is the best optimized for background services. WorKManager is compatible with all versions of API either for onetime Job required or periodically required to execute the job.

WorkManager is intended for tasks that require a guarantee that the system will run them even if the app exits.

Why is required WorkManager?

Whenever you need to execute the long-running task in the background it means it does not matter your application is running or not. WorkManager provides the guarantee that the Job will surely execute by the System either it is OneTime Job or Schedule Job on time demand. For example, Whenever You need to sync the remote data from the server or upload files to remote servers or fetch some data periodically from the local database kind of job.

There are many benefits to using the WorkManager.

  1. it is compatible with all versions of Android API.
  2. It is optimized for background service for on-time demand to execute the Job.
  3. Execute the Job while the Constraint is satisfied.
  4. Best optimized by maintaining the device’s health.
  5. Execute the job either parallel or synchronous.
  6. Easily create the Chaining of Jobs

How to use the WorkManager?

To use the work manager is required a few dependencies to add to your project Gradle file.

 
// work manager
    implementation "android.arch.work:work-runtime-ktx:1.0.1"

Let’s create the sample app to learn the basics of the use case of use the WorkManager. Let’s take a simple example, Whenever a button press by a user, WorkManager executes the One Time job and sends Notification that work is done. Here we can also Observer the Status of the work manager to monitor the job status.

Here I want to set one constraint that the job will execute only when the device is in charging constraint and send input data as a parameter to WorkManager.

val powerConstraint = Constraints.Builder().setRequiresCharging(true).build()
 val taskData = Data.Builder().putString(MESSAGE_STATUS, "Notify Done.").build()

Here I have done these two parameters configured. Now I want to create the One Time Job to set these parameters to build the Job.

 val request = OneTimeWorkRequest.Builder(NotifyWorker::class.java)
            .setConstraints(powerConstraint).setInputData(taskData).build()

Now I need to create the NotifyWorker Class which extends the Worker Class of WorkManager.

class NotifyWorker(context: Context, workParamters: WorkerParameters) :
    Worker(context, workParamters) {

    override fun doWork(): Result {

        // get the input and do the task
        return Result.success(object)
    }
}

 

Ok, Now how can I start this Job. It is very simple to enqueue the job.

btn_send.setOnClickListener {
            WorkManager.getInstance().enqueue(request)
        }

 

Now the next question, how can we observe the status of the Job?
worker.getWorkInfoByIdLiveData(request.id).observe(this, Observer { workInfo ->
            workInfo.let {
                if (it.state.isFinished) {
                  // do the task
                } 
            }
        })

 

Let’s provide the complete source code of Worker class and Activity Class to better understanding.

class NotifyWorker(context: Context, workParamters: WorkerParameters) :
    Worker(context, workParamters) {

    override fun doWork(): Result {

        val taskData = inputData
        val taskDataString = taskData.getString(WorkerActivity.MESSAGE_STATUS)

        showNotification("Work Manager", taskDataString.toString())

        val outputData = Data.Builder().putString(WORK_RESULT, "Task Finished").build()

        return Result.success(outputData)
    }

    private fun showNotification(task: String, desc: String) {

        val manager =
            applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        val channelId = "message_channel"
        val channelName = "message_name"

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

            val channel =
                NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT)
            manager.createNotificationChannel(channel)
        }

        val builder = NotificationCompat.Builder(applicationContext, channelId)
            .setContentTitle(task)
            .setContentText(desc)
            .setSmallIcon(R.mipmap.ic_launcher)

        manager.notify(1, builder.build())

    }

    companion object {
        const val WORK_RESULT = "work_result"
    }
}

 

In the Activity Class, we need to instantiate the Worker Class to start the Job.

class WorkerActivity : AppCompatActivity() {

    private lateinit var worker: WorkManager
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.work_activity)

        worker = WorkManager.getInstance()

        val powerConstraint = Constraints.Builder().setRequiresCharging(true).build()

        val taskData = Data.Builder().putString(MESSAGE_STATUS, "Notify Done.").build()

        val request = OneTimeWorkRequest.Builder(NotifyWorker::class.java)
            .setConstraints(powerConstraint).setInputData(taskData).build()

        btn_send.setOnClickListener {
            worker.enqueue(request)
        }

        worker.getWorkInfoByIdLiveData(request.id).observe(this, Observer { workInfo ->
            workInfo.let {
                if (it.state.isFinished) {
                    val outputData = it.outputData
                    val taskResult = outputData.getString(NotifyWorker.WORK_RESULT)
                    txt_input.text = taskResult
                } else {
                    val workStatus = workInfo.state
                    txt_input.text = workStatus.toString()
                }
            }
        })

    }

    companion object {
        const val MESSAGE_STATUS = "message_status"
    }
}

 

In the Layout file, I just added a button and Text View to show the status of the running job.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:text="Send"
        android:id="@+id/btn_send"
        android:layout_gravity="center"
        android:gravity="center"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <TextView
        android:id="@+id/txt_input"
        android:layout_gravity="center"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>

 

 

Now the next is how can we create the hourly repeated unique periodic job to trigger by the system. Here is the sample of periodic job.

fun scheduleWork(tag: String) {
        val constraints = Constraints.Builder()
            .setRequiresCharging(true)
            .build()
        val work = PeriodicWorkRequestBuilder<NotifyWorker>(1, TimeUnit.HOURS).setConstraints(constraints)
            .build()
        worker.enqueueUniquePeriodicWork(tag, ExistingPeriodicWorkPolicy.KEEP , work)
    }

 

That’s all guys, I hope this article helps you the understand the basic of WorkManager to run the task in the background.

Wrapping 

Now we have a good understanding of the new android Jetpack Component WorkManager. We have played with a sample project to learn the basic concept of WorkManager. I personally like this change from Google. You can get the full Github source code of Jetpack Component. So my next tutorial, we will learn some other jetpack Components in detail, ok till then enjoy your healthy day.

If you are wondering to learn Android then Please learn from Android category and wondering to learn Kotlin then Kotlin Category will help you. If you want to learn all the python article, then learn from the python category.

Happy Coding 🙂

5 1 vote
Article Rating

Recent Posts

Hide your production API key or any sensitive data in Android

Hi everyone, In this article, we are going to learn how to hide the production… Read More

2 years ago

How to handle the localisation or multi language support in android with examples?

Hello everyone, Today in this article, we are going to learn about localisation to support… Read More

2 years ago

How to convert any callback to Coroutines and use them in Kotlin Android?

Hello everyone, In this article, we are going to learn something to handle the callback… Read More

2 years ago

Request Permission Launcher with Kotlin in Android

In this article, we are learning about the run time permissions for request permission launchers.… Read More

2 years ago

Implement the SMS User Consent API and SMS Retriever API in Android

Hello everyone. In my last tutorial, we learned about the Jetpack Compose introduction and about applying the… Read More

3 years ago

Jetpack Compose Coroutine flow with LiveData/ViewModel in Android

Hello everyone, In this article, we are going to learn about the Jetpack Compose with… Read More

3 years ago