topic: Work Manager

Hard Prerequisites
IMPORTANT: Please review these prerequisites, they include important information that will help you with this content.
  • TOPICS: Internet Data and Images
  • Working With Android WorkManager Using Kotlin

    An ideal way of scheduling future tasks with backward compatibilit

    The WorkManager is an API which can schedule your future asynchronous tasks and can run them in the background. The tasks assigned to the WorkManager are executed even if the user is outside the app or app is closed. WorkManager can run your task(s) for one time only as well as many times or periodically.

    Features of WorkManager

    • It provides backward compatibility up to API level 14
    • You can add one or many constraints, such as execute tasks only when phone is charging or phone is restarted etc.
    • You can schedule onetime task or periodic tasks
    • You can also chain multiple tasks. For instance, task (B) should only be executed when task (A) is finished.
    • It can help you to execute tasks on particular events.

    Note: WorkManager is not intended for in-process background work that can safely be terminated if the app process goes away or for tasks that require immediate execution.

    The classes

    • Worker: The work needed to be done is defined here.
    • WorkRequest: It decides which worker class is going to be executed. It’s an abstract class, so we’re going to use its direct classes, and they’re OneTimeWorkRequest and PeriodWorkRequest.
    • WorkManger: It enqueues and manages the work request.
    • WorkInfo: It gives us information about the work, whether its success, running or failed.

    Let’s start coding now…

    What we’ll create?

    We’re going to create a notification in the background and this notification can be created only once because we’re using the OneTimeWorkRequest class. Later on, We’ll use some constraints to generate the notification on the basis of events.

    First of all, add the following dependency.

    implementation "androidx.work:work-runtime-ktx:2.3.4"
    

    We’ll create our worker class first by extending the Worker class, and override its doWork() method for background processing. When doWork() method is called by WorkManager, then it calls user defined method createNotification().

    package com.workmanagerdemo
    
    import android.app.NotificationChannel
    import android.app.NotificationManager
    import android.content.Context
    import android.os.Build
    import androidx.core.app.NotificationCompat
    import androidx.work.Worker
    import androidx.work.WorkerParameters
    
    class MyWork(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
    
        override fun doWork(): Result {
            createNotification("Background Task", "This notification is generated by workManager")
            return Result.success()
        }
    
        fun createNotification(title: String, description: String) {
    
            var notificationManager =
                applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                val notificationChannel =
                    NotificationChannel("101", "channel", NotificationManager.IMPORTANCE_DEFAULT)
                notificationManager.createNotificationChannel(notificationChannel)
            }
    
            val notificationBuilder = NotificationCompat.Builder(applicationContext, "101")
                .setContentTitle(title)
                .setContentText(description)
                .setSmallIcon(R.drawable.ic_launcher_background)
    
            notificationManager.notify(1, notificationBuilder.build())
    
        }
    }
    

    In our MainActivity.kt class, I’ve created a button, when user clicks on the button, then immediately notification gets generated.

    package com.workmanagerdemo
    
    import androidx.appcompat.app.AppCompatActivity
    import android.os.Bundle
    import android.widget.Toast
    import androidx.lifecycle.Observer
    import androidx.work.OneTimeWorkRequest
    import androidx.work.OneTimeWorkRequestBuilder
    import androidx.work.WorkManager
    import kotlinx.android.synthetic.main.activity_main.*
    
    class MainActivity : AppCompatActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            val request = OneTimeWorkRequestBuilder<MyWork>().build()
    
    
            btnClick.setOnClickListener {
    
                WorkManager.getInstance(this).enqueue(request)
            }
    
            WorkManager.getInstance(this).getWorkInfoByIdLiveData(request.id)
                    .observe(this, Observer {
    
                        val status: String = it.state.name
                        Toast.makeText(this,status, Toast.LENGTH_SHORT).show()
                    })
    
        }
    }
    

    Here, I’m creating the object of OneTimeWorkRequest and passing the class name of our MyWork class. In the real world, we can have many worker classes, so which class should be executed is decided by this request object.

    val request = OneTimeWorkRequestBuilder<MyWork>().build()
    

    As user clicks on the button, WorkManager enqueues the request.

    WorkManager.getInstance(this).enqueue(request)
    

    Here, we’re creating a toast to display the status of our task, whether its RUNNING, SUCCESS, and FAILED. The getWorkInfoByIdLiveData method takes the request id and gives the information about the task.

    WorkManager.getInstance(this).getWorkInfoByIdLiveData(request.id)
                .observe(this, Observer {
    
                    val status: String = it.state.name
                    Toast.makeText(this,status, Toast.LENGTH_SHORT).show()
                })
    
    }
    

    Now run your application and click on the button, you’ll see a notification.

    Now we’ll see how we can add constraints to create notification only when the phone is charging.

    Add the following line of code to create the constraint and modify your request object. In the request object, I’m just setting the constraints and that’s it. Now notification will only be generated when this particular criterion is met.

    val constraints = Constraints.Builder()
            .setRequiresCharging(true)
            .build()
    var request = OneTimeWorkRequestBuilder<MyWork>()
            .setConstraints(constraints)
            .build()
    

    Note: When multiple constraints are specified, your task will run only when all the constraints are met.

    If you click on the button and your phone is not charging, then you’ll see a status saying “Enqueued”, this means that your request has been put in the queue and this will only execute when your phone will be charging.

    If you’re facing any problem running the code, then you can download this project from this Github account.

    Conclusion

    We’ve seen how we can use WorkManager class to perform some background processing.


    RAW CONTENT URL