DEV Community

Cover image for Using WorkManager on Android | Kotlin
Aayush Gupta
Aayush Gupta

Posted on • Updated on

Using WorkManager on Android | Kotlin

WorkManager library allows you to schedule running your tasks on certain conditions as well as monitor, control, and cancel them. This is really useful in many scenarios. In this article, I will show you the basics of how you can use it in Kotlin.

Dependencies

Add dependency on the WorkManager library in your app's build.gradle file.

dependencies {
    // WorkManager
    def work_version = "2.5.0"
    implementation "androidx.work:work-runtime-ktx:$work_version"
}
Enter fullscreen mode Exit fullscreen mode

Usage

Worker Class Implementation

To use WorkManager, we need to create a new class that will extend to the Worker class while taking context and work parameters as arguments. Afterward, we will override the doWork() function in the class in which we will store our task which we want to run using WorkManager.

In my case, I will name this new class MainActivityWorkManager.kt. Here is how it looks like:

class MainActivityWorkManager(context: Context, workerParameters: WorkerParameters) :
    Worker(context, workerParameters) {

    override fun doWork(): Result {
        //TODO: implement the task
    }

}
Enter fullscreen mode Exit fullscreen mode

The doWork() function returns a type of Result using which one can query the result of the work.

As for our example, let's display a test notification. To do this, we will need to create a new notification channel and show the notification using it. I won't be explaining how to do that as that's out of the scope of this article.

Here is how my code will look like once the class implementation is finished.

package dev.theimpulson.workmanagerexample

import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.work.Worker
import androidx.work.WorkerParameters

class MainActivityWorkManager(context: Context, workerParameters: WorkerParameters) :
    Worker(context, workerParameters) {

    private val CHANNEL_ID = "MainActivity"

    val notification = NotificationCompat.Builder(context, CHANNEL_ID)
        .setSmallIcon(R.drawable.ic_android_black_24dp)
        .setContentTitle("Hello World")
        .setContentText("This is your test notification")
        .setPriority(NotificationCompat.PRIORITY_HIGH)
        .build()

    override fun doWork(): Result {
        createNotificationChannel()

        with(NotificationManagerCompat.from(applicationContext)) {
            notify(1, notification)
        }

        return Result.success()
    }

    fun createNotificationChannel() {
        val channel = NotificationChannel(
            CHANNEL_ID,
            "Test Notification",
            NotificationManager.IMPORTANCE_HIGH
        ).apply {
            description = "This is your MainActivity's test channel"
        }
        val notificationManager =
            applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.createNotificationChannel(channel)
    }
}
Enter fullscreen mode Exit fullscreen mode

The key takeaway from the above code is that, whatever code we want to schedule to run via WorkManager, put it in the doWork() function.

WorkRequest Implentation

Now that we have defined the work in the class, we need to make a request. There are 2 types of supported WorkRequests:

  • OneTimeWorkRequest that only runs once, and
  • PeriodicWorkRequest that runs periodically.

Creating both types of requests is pretty easy. We will create a new val which will store these requests. Create an instance using OneTimeWorkRequestBuilder or PeriodicWorkRequestBuilder as necessary to do this.

Here is how an instance with OneTimeWorkRequestBuilder will look:

val workRequest = OneTimeWorkRequestBuilder<MainActivityWorkManager>()
       .build()

Enter fullscreen mode Exit fullscreen mode

and here is how an instance with PeriodicWorkRequestBuilder will look:

val workRequest =
       PeriodicWorkRequestBuilder<MainActivityWorkManager>(1, TimeUnit.HOURS)
           .build()
Enter fullscreen mode Exit fullscreen mode

For the sake of simplicity, I will use OneTimeWorkRequestBuilder while proceeding further with the article. Creating both types of requests is similar to each other except for the difference of specifying time in periodic requests.

WorkManager Implementation

Now as our worker and work request both are ready, we can use WorkManager to queue the work. To do this, simply get an instance of the WorkManager using the getInstance method with context and call enqueue on it with your work request as an argument.

WorkManager
    .getInstance(it.context)
    .enqueue(workRequest)
Enter fullscreen mode Exit fullscreen mode

Considering I have kept my work request and manager inside my button's setOnClickListener function, I am getting the context using it.

Work Constraints

You can use Constraints to define some constraints which will ensure that your work requests only run if they are satisfied.

To do this, use Constraints.Builder() to build a new constraint and use setConstraints method on the work request which takes the above-defined constraint as an argument.

Currently, 5 types of constraints can be defined which you can check on developer.android.com.

Here is an example of a constraint that ensures that the work requests only runs when the device is charging.

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

val workRequest = OneTimeWorkRequestBuilder<MainActivityWorkManager>()
    .setConstraints(constraints)
    .build()
Enter fullscreen mode Exit fullscreen mode

Here is how my MainActivity.kt looks after implementing everything:

package dev.theimpulson.workmanagerexample

import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.work.Constraints
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import dev.theimpulson.workmanagerexample.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.button.setOnClickListener {
            val constraints = Constraints.Builder()
                .setRequiresCharging(true)
                .build()

            val workRequest = OneTimeWorkRequestBuilder<MainActivityWorkManager>()
                .setConstraints(constraints)
                .build()

            WorkManager
                .getInstance(it.context)
                .enqueue(workRequest)

            Toast.makeText(it.context, "WorkManager Request Made", Toast.LENGTH_SHORT).show()
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Observing and Cancelling Enqueued Work Requests

You can also observe the progress and cancel the enqueued work requests if required. Doing this fairly easy and is documented in android documentation as well. Check them out here:

and that's it. You can now use WorkManager to queue your work requests to run at any time you need.

Top comments (0)