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

3

15

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?

Kinchen answered 12/7, 2019 at 17:14 Comment(0)
M
11

You can always use job.invokeOnCompletion without having to rely on the onStopped callback for CoroutineWorker. 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()
    }
}


Mindszenty answered 15/7, 2019 at 19:33 Comment(4)
Working on cancellation as well for me.Cheeks
What does this mean "just use coroutineContext[Job]"? @VladEmad
Can you please show some example to see how to use coroutineContext[Job]?Emad
Really useful, Im adding this in my BaseCoroutineWorker classDelano
S
6

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

Saccharate answered 1/4, 2021 at 7:28 Comment(0)
L
4

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()
    }
}
Lindeberg answered 3/5, 2022 at 6:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.