WorkManager is an Android background tasks management system which came with Jetpack. We use it to run postponed background work. It will run even if the app is closed.
WorkManager is not for tasks that need to be run in a background thread, but they don’t need to survive the process death. Use Kotlin’s coroutines instead. WorkManager is for periodic work requests or one time work requests that need to run even if the user closses the App or needs constraints such as make sure the device is charging or be sure it uses WIFI.
It’s possible to chain multiple Workers together to run one after another.
Implementation
Add this to your build.gradle
file.
dependencies {
def work_version = "2.3.4"
implementation "androidx.work:work-runtime-ktx:$work_version"
}
One Time Work Requests
Create a worker class. This will be executed by the work manager instance when conditions are met.
class UploadWorker(context: Context, params: WorkerParameters): Worker(context, prams) {
override fun doWork(): Result {
try {
// add your work here
return Result.success()
} catch(e: Exception) {
return result.failure()
}
}
}
Now set it up.
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setOneTimeWorkRequest()
}
private fun setOneTimeWorkRequest() {
val uploadRequest = OneTimeWorkRequest.Builder(UploadWorker::class.java)
.build()
WorkManager.getInstance(applicationContext)
.enqueue(uploadRequest)
}
}
Get status updates
For each work request, WorkManager allows us to get a LiveData<WorkInfo>
. By observing it, we can determine the current status.
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setOneTimeWorkRequest()
}
// change this
private fun setOneTimeWorkRequest() {
val workManager = WorkManager.getInstance(applicationContext)
val uploadRequest = OneTimeWorkRequest.Builder(UploadWorker::class.java)
.build()
workManager.enqueue(uploadRequest)
workManager.getWorkInfoByIdLiveData(uploadRequest.id)
.observe(this, Observer {
// this is just a TextView to show it off
textView.text = it.state.name
})
}
}
Set up constraints
Sometimes we want to set up constraints. For example, if we want to download a large video, this consumes too much battery and we want to do it only if the battery’s connected.
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setOneTimeWorkRequest()
}
private fun setOneTimeWorkRequest() {
val workManager = WorkManager.getInstance(applicationContext)
// added this
val constraints = Constraints.Builder()
.setRequiresCharging(true)
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
val uploadRequest = OneTimeWorkRequest.Builder(UploadWorker::class.java)
// added this
.setConstraints(constraints)
.build()
workManager.enqueue(uploadRequest)
workManager.getWorkInfoByIdLiveData(uploadRequest.id)
.observe(this, Observer {
// this is just a TextView to show it off
textView.text = it.state.name
})
}
}
Pass data to workers
Sometimes we need to pass data to the workers. It’s also possible to send data from the Workers to the Activity.
class MainActivity: AppCompatActivity() {
// added this
companion object {
const val KEY_COUNT_VALUE = "key_count"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setOneTimeWorkRequest()
}
private fun setOneTimeWorkRequest() {
val workManager = WorkManager.getInstance(applicationContext)
// added this
val data = Data.Builder()
.putInt(KEY_COUNT_VALUE, 125)
.build()
val constraints = Constraints.Builder()
.setRequiresCharging(true)
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
val uploadRequest = OneTimeWorkRequest.Builder(UploadWorker::class.java)
.setConstraints(constraints)
// added this
.setInputData(data)
.build()
workManager.enqueue(uploadRequest)
workManager.getWorkInfoByIdLiveData(uploadRequest.id)
.observe(this, Observer {
// this is just a TextView to show it off
textView.text = it.state.name
})
}
}
We get it like this at our Worker.
class UploadWorker(context: Context, params: WorkerParameters): Worker(context, prams) {
override fun doWork(): Result {
try {
// 0 is the default value
val count = inputData.getInt(MainActivity.KEY_COUNT_VALUE, 0)
// add your work here
return Result.success()
} catch(e: Exception) {
return result.failure()
}
}
}
Periodic work requests
For now, Android Jetpack has a minimum repeat time of 15 minutes. The only difference is we need use PeriodicWorkRequest
class instead.
fun setPeriodicWorkRequest() {
val periodicWorkRequest = PeriodicWorkRequest
.Builder(DownloadingWorker::class.java, 16, TimeUnit.MINUTES)
.build()
WorkManager.getInstance(applicationContext).enqueue(periodicWorkRequest)
}