Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I execute cleanup code in my CoroutineWorker when onStopped is final?

I upgraded to WorkManager 2.1.0 and tried to use some of the Kotlin extensions including CoroutineWorker. My worker was extending androidx.work.Worker previously and it was executing cleanup code by overriding onStopped. Why is onStopped final in CoroutineWorker? Is there any other way for me to execute cleanup code after the CoroutineWorker is stopped?

According to this blog post, is this supposed to be a feature?

like image 656
B W Avatar asked Jul 12 '19 17:07

B W


People also ask

How do I execute a specific action when a coroutine is cancelled?

Let’s say that you want to execute a specific action when a coroutine is cancelled: closing any resources you might be using, logging the cancellation or some other cleanup code you want to execute. There are several ways we can do this:

How does coroutineworker handle work stoppages?

CoroutineWorker handles stoppages automatically by cancelling the coroutine and propagating the cancellation signals. You don't need to do anything special to handle work stoppages. You can also bind a worker to a specific process by using RemoteCoroutineWorker , an implementation of ListenableWorker.

What is an example of cleanup in C++?

One example of such cleanup is calling Close on a FileStream immediately after use instead of waiting for the object to be garbage collected by the common language runtime, as follows: To turn the previous code into a try-catch-finally statement, the cleanup code is separated from the working code, as follows.

What is the difference between coroutineworker and worker?

Note that CoroutineWorker.doWork () is a suspending function. Unlike Worker, this code does not run on the Executor specified in your Configuration. Instead, it defaults to Dispatchers.Default. You can customize this by providing your own CoroutineContext.


3 Answers

You can always use job.invokeOnCompletetion without having to rely in the onStopped callback for CoroutineWorker. For e.g.

import android.content.Context
import android.util.Log
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope

class TestWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {

    companion object {
        private const val TAG = "TestWorker"
    }

    override suspend fun doWork(): Result {
        return coroutineScope {
            val job = async {
                someWork()
            }

            job.invokeOnCompletion { exception: Throwable? ->
                when(exception) {
                    is CancellationException -> {
                        Log.e(TAG, "Cleanup on completion", exception)
                        // cleanup on cancellations
                    }
                    else -> {
                        // do something else.
                    }
                }
            }

            job.await()
        }
    }

    suspend fun someWork(): Result {
        TODO()
    }
}


like image 168
Rahul Avatar answered Oct 13 '22 09:10

Rahul


From Kotlin documentation:

Cancellable suspending functions throw CancellationException on cancellation which can be handled in the usual way. For example, try {...} finally {...} expression and Kotlin use function execute their finalization actions normally when a coroutine is cancelled. Coroutines documentation

That means that you can clean up coroutine code in usual, Java/Kotlin way with try and finally:

    override suspend fun doWork(): Result {
        return try {
            work()
            Result.success()
        } catch (e: Exception) {
            Result.failure()
        } finally {
            cleanup()
        }
    }

Note that you can't suspend in catch and finally. If you do, use withContext(NonCancellable) NonCancellable documentation

like image 6
Michal Engel Avatar answered Oct 13 '22 11:10

Michal Engel


Just catch CancellationException

override suspend fun doWork(): Result {
    return try {
        // here do work
        return Result.success()
    } catch (e: CancellationException) {
        // here clean up
        return Result.failure()
    }
}
like image 1
Vlad Avatar answered Oct 13 '22 09:10

Vlad