Android WorkManager Jetpack for Background Work
Android WorkManager is not intended for an in-process background task that can be safely terminated if the app process runs or for tasks requiring immediate execution. Android WorkManager provides great feature Task Chaining. We can define multiple tasks if we want. New task can start only after old task is finished.
Job Scheduler is available only in android lollipop or after versions. But Android WorkManager is compatible with all android versions. So We do not need to check android version before use of android workmanager.
Minimum duration of android workmanager is 15 minutes. So your work execution can repeat only after a minimum 15 minutes. If you want to repeat your work after less than 15 minutes then you need to create foreground service.
Add the below dependency in your app level build.gradle file
dependencies { implementation 'androidx.work:work-runtime-ktx:2.3.4' }
Create a layout file for activity
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:id="@+id/btn_one_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Start One Time Request" android:textAllCaps="false" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.4" /> <Button android:id="@+id/btn_periodic" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Start Periodic Request" android:textAllCaps="false" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.6" /> </androidx.constraintlayout.widget.ConstraintLayout>
Add Work Constraints if needed
val constraints = Constraints.Builder() .setRequiresDeviceIdle(true) .setRequiresCharging(true) .build() val oneTimeReq = OneTimeWorkRequest.Builder(MyWorker::class.java) .setConstraints(constraints) .build()
Add Initial Delays if needed
val oneTimeReq = OneTimeWorkRequest.Builder(MyWorker::class.java) .setInitialDelay(2,TimeUnit.MINUTES) .build()
Add Input Parameters if needed
val data = Data.Builder() .putString(“channel_id”,”periodic_work”) .putString(“title”, “Periodic Request”) .putString(“message”, “This notification is from Periodic Request”) .build() val periodicReq = PeriodicWorkRequest.Builder(MyWorker::class.java,15,TimeUnit.MINUTES) .setInputData(data) .build()
Get Data in Worker class
class MyWorker(private val context: Context, private val workerParams: WorkerParameters) : Worker(context, workerParams) { override fun doWork(): Result { val getData = workerParams.inputData val channelId = getData.getString(“channel_id”) val title = getData.getString(“title”) val message = getData.getString(“message”) context.sendNotification(channelId,title,message) return Result.success() } }
Execute WorkRequests
For OneTimeWorkRequest:
OneTimeWorkRequest is used to perform work only once.
val oneTimeReq = OneTimeWorkRequest.Builder(MyWorker::class.java) .setConstraints(constraints) .setInputData(data) .build() val workManager = WorkManager.getInstance(this) workManager.enqueue(oneTimeReq)
For PeriodicWorkRequest:
val periodicReq = PeriodicWorkRequest.Builder(MyWorker::class.java,15,TimeUnit.MINUTES) .setConstraints(constraints) .setInputData(data) .build() val workManager = WorkManager.getInstance(this) workManager.enqueueUniquePeriodicWork(“start_periodic_work”,ExistingPeriodicWorkPolicy.REPLACE,periodicReq)
Cancelling WorkRequests
For OneTimeWorkRequest:
workManager.cancelWorkById(oneTimeReq.id)
For PeriodicWorkRequest:
workManager.cancelWorkById(periodicReq.id)
Final Code
package com.example.workmanagersample import android.app.* import android.content.Context import android.os.Build import androidx.core.app.NotificationCompat import androidx.work.Worker import androidx.work.WorkerParameters class MyWorker(private val context: Context, private val workerParams: WorkerParameters) : Worker(context, workerParams) { override fun doWork(): Result { val getData = workerParams.inputData val channelId = getData.getString("channel_id") val title = getData.getString("title") val message = getData.getString("message") context.sendNotification(channelId,title,message) return Result.success() } private fun Context.sendNotification( channelId: String?, contentTitle: String?, contentText: String? ) { try { // Get an instance of the Notification manager val mNotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager // Android O requires a Notification Channel. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // Create the channel for the notification val mChannel = NotificationChannel(channelId, getString(R.string.app_name) , NotificationManager.IMPORTANCE_HIGH) // Set the Notification Channel for the Notification Manager. mNotificationManager.createNotificationChannel(mChannel) } // Get a notification builder that's compatible with platform versions >= 4 val builder = NotificationCompat.Builder(this) // Define the notification settings. builder.setSmallIcon(R.drawable.ic_launcher_foreground) .setContentTitle(contentTitle) .setContentText(contentText) // Set the Channel ID for Android O. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { channelId?.let { builder.setChannelId(it) } // Channel ID } else { builder.priority = Notification.PRIORITY_HIGH } // Dismiss notification once the user touches it. builder.setAutoCancel(true) // Issue the notification mNotificationManager.notify(0, builder.build()) } catch (e: Exception) { e.printStackTrace() } } }
package com.example.workmanagersample import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import androidx.work.* import kotlinx.android.synthetic.main.activity_main.* import java.util.concurrent.TimeUnit class MainActivity : AppCompatActivity() { private lateinit var workManager: WorkManager private lateinit var oneTimeReq: OneTimeWorkRequest private lateinit var periodicReq: PeriodicWorkRequest override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) workManager = WorkManager.getInstance(this) btn_one_time.tag = "stopped" btn_periodic.tag = "stopped" btn_one_time.setOnClickListener { if(it.tag == "stopped"){ btn_one_time.tag = "started" btn_one_time.text = "Cancel One Time Request" startOneTimeRequest() } else{ btn_one_time.tag = "stopped" btn_one_time.text = "Start One Time Request" workManager.cancelWorkById(oneTimeReq.id) } } btn_periodic.setOnClickListener { if(it.tag == "stopped"){ btn_periodic.tag = "started" btn_periodic.text = "Cancel Periodic Request" startPeriodicRequest() } else{ btn_periodic.tag = "stopped" btn_periodic.text = "Start Periodic Request" workManager.cancelWorkById(periodicReq.id) } } } private fun startOneTimeRequest(){ val constraints = Constraints.Builder() .build() val data = Data.Builder() .putString("channel_id","one_time_work") .putString("title", "One Time Request") .putString("message", "This notification is from One Time Request") .build() oneTimeReq = OneTimeWorkRequest.Builder(MyWorker::class.java) .setConstraints(constraints) .setInputData(data) .build() workManager.enqueue(oneTimeReq) } private fun startPeriodicRequest(){ val constraints = Constraints.Builder() .build() val data = Data.Builder() .putString("channel_id","periodic_work") .putString("title", "Periodic Request") .putString("message", "This notification is from Periodic Request") .build() periodicReq = PeriodicWorkRequest.Builder(MyWorker::class.java,15,TimeUnit.MINUTES) .setConstraints(constraints) .setInputData(data) .build() workManager.enqueueUniquePeriodicWork("start_periodic_work",ExistingPeriodicWorkPolicy.REPLACE,periodicReq) } }
Really nice example
Thanks for demo
its a wonderful article