“This is the 13th day of my participation in the First Challenge 2022. For details: First Challenge 2022”

A, the WorkManager

WorkManager is the recommended solution for persistent work. Work is persistent when the schedule is maintained through application restarts and system restarts. Since most background processing is best done through persistence work, WorkManager is the primary recommended API for background processing.

Periodic tasks registered with WorkManager do not necessarily execute on time. This is not a Bug, but rather the system may try to reduce power consumption by putting together several tasks that trigger events close to each other. This can significantly reduce the number of CPU awakenings, thus effectively increasing battery life.

Note: WorkManager and Seriver are not a concept, nor are they directly related. Seriver is one of the four components of the Android system. WorkManager is just a tool for processing scheduled tasks.

Some of these concepts are already in place last time, so let’s go ahead and start using Kotlin.

Basic usage of WorkManager

2.1 Adding a Dependency

Add the following dependencies to your app/build.gradle file:

dependencies {
    def work_version = "2.7.1"

    // Kotlin + coroutines
    implementation "androidx.work:work-runtime-ktx:$work_version"
}
Copy the code

2.2 use the WorkManager

2.2.1 Defining tasks

The definition task must inherit from the Worker class and call its constructor (unique). Override the doWork() method.

Note: The doWork() method runs asynchronously on a background thread provided by the WorkManager, so you can safely perform time-consuming operations here.

/** * Create time: 2022/1/27 * Function: Define a task (Kotlin) */
class KotlinTestWork(appContext: Context, workerParams: WorkerParameters):
    Worker(appContext, workerParams) {
    override fun doWork(a): Result {
        // Perform time-consuming operations
        doSmothing()
        return Result.success()
    }

    private fun doSmothing(a) {
        // This is just a simple print
        Log.e("KotlinTestWork"."KotlinTestWork performing doWork")}}Copy the code

The Result returned from doWork() informs the WorkManager service whether the work was successful and whether the work should be retried in case of failure:

  • Result.success() : success.
  • Result.failure() : failure.
  • Result.retry() : The work fails and can be re-executed using the setBackoffCriteria() method of workRequest.Builder.

2.2.2 Build task request

WorkRequest.Worker defines the unit of work, and WorkRequest (and its subclasses) defines how and when it should run. In the simplest case, you can use OneTimeWorkRequest.

        // Build the task request
        // Method 1: simple Work without additional configuration
        val fromWorkRequest: WorkRequest = OneTimeWorkRequest.from(KotlinTestWork::class.java)
        // Method 2: complex Work, which can be configured using the builder
        val workRequest: WorkRequest =
            OneTimeWorkRequestBuilder<KotlinTestWork>().build()
Copy the code

2.2.3 Submitting WorkRequest to the System

Finally, the WorkRequest built tasks are submitted to the WorkManager using the enqueue() method. The system will run at the right time.

        binding.btnDowork.setOnClickListener {
            // Submit WorkRequest to the system
            WorkManager
                .getInstance(this)
                .enqueue(workRequest)
        }
Copy the code

Advanced usage of WorkManager

3.1 the task

  • Observe the task
  • The value of
  • The constraint
    @RequiresApi(Build.VERSION_CODES.N)
    fun complexWork(a){
        // Constraints
// val constraints = Constraints.Builder().apply {
// setRequiresDeviceIdle(true)// Whether the device is idle when triggered
// setRequiresCharging(true
// setRequiredNetworkType(networktype.unmetered)// Indicates the network status
SetRequiresBatteryNotLow (true)// Specifies whether the device battery should not fall below the critical threshold
// setRequiresStorageNotLow(true)// Specifies whether the available storage of the device should not fall below the critical threshold
//// addContentUriTrigger(myUri,false)// Whether {@link WorkRequest} updates should be run when specifying content {@link android.net.Uri}
// }.build()
        / / value
        val data = Data.Builder().apply {
            putString("name"."Scc")
            putInt("age".25)
        }.build()
        // Build task
        complexWorkRequest =
            OneTimeWorkRequestBuilder<KotlinTestWorkInfo>()
                // Execute after 1 minute, of course you can specify the unit with this method (ms/s/min/hour/day)
                .setInitialDelay(1, TimeUnit.SECONDS)
                .addTag("complex")
// .setConstraints(constraints)
                .setInputData(data)
                .build()
        binding.btnObserveWorkinfo.setOnClickListener {
            Log.e("Work"."start")
            val workManager = WorkManager.getInstance(this)
            workManager.getWorkInfoByIdLiveData(complexWorkRequest.id)
                .observe(this){
                    Log.e("Work"."State:"+it.state)
                    if(! it.outputData.getString("work").isNullOrBlank()){
                        var msg = it.outputData.getString("work") +":"+it.outputData.getInt("length".5)
                        Log.e("Work"."Data:"+msg)
                    }
                }
            workManager.enqueue(complexWorkRequest)
        }
    }
Copy the code

3.2 Canceling or Stopping a Task

  • Cancel a task by Id
  • Cancel the task by Tag
  • Cancel all tasks
            WorkManager.getInstance(this).cancelAllWorkByTag("complex")
            WorkManager.getInstance(this).cancelWorkById(complexWorkRequest.id)
            WorkManager.getInstance(this).cancelAllWork()
Copy the code

3.3 Chain tasks

Suppose we have three separate background tasks: get an image, compress an image, and upload an image. So if we want to do this, we can do it using chained tasks.

        // chain call
        WorkManager.getInstance(this)
            // Run parallel
            .beginWith(listOf(work1, work2, work3))
            // Continue to invoke the compression task after performing the signature operation
            .then(cache)
            // The upload task is invoked after the compression task is executed
            .then(upload)
            // Add to the WorkManager queue
            .enqueue()
Copy the code
  • BeginWith: beginWith() means to begin a chained task.
  • Then: Use the then() method to link any subsequent tasks.

This article is more about using Kotlin to practice WorkManager. For more concept descriptions and Java practices, check out # Jetpack WorkManager. .