A Job has a very simple design life cycle. Its โCompletedโ state is final, very similar to the โDestroyedโ state of Android Activity . Thus, the parent Job best associated with Activity , as described in the manual. You must cancel parental work if and only if the action is destroyed. Since a shattered action cannot be reused, you will never encounter the need to reuse its work.
The recommended approach to getting started on every click is to use actors because they help you avoid unnecessary concurrency. The manual shows how to start them with each click, but does not show how to undo the current action.
You will need a fresh instance of Job combined with withContext so that the code block is canceled separately from everything else:
fun View.onClick(action: suspend () -> Unit) { var currentJob: Job? = null // to keep a reference to the currently running job // launch one actor as a parent of the context job // actor prevent concurrent execution of multiple actions val eventActor = actor<Unit>(contextJob + UI, capacity = Channel.CONFLATED) { for (event in channel) { currentJob = Job(contextJob) // create a new job for this action try { // run an action within its own job withContext(currentJob!!) { action() } } catch (e: CancellationException) { // we expect it to be cancelled and just need to continue } } } // install a listener to send message to this actor setOnClickListener { currentJob?.cancel() // cancel whatever job we were doing now (if any) eventActor.offer(Unit) // signal to start next action when possible } }
An actor is always active until his parental assignment (attached to the activity) is canceled. The actor waits for clicks and launches an action for each click. However, each action call ends in its own Job with the withContext block, so it can be canceled separately from its parent job.
Please note that this code works gracefully for actions that cannot be undone or it just takes some time to cancel. An action may need to clear resources when it is canceled, and since this code uses an actor, it ensures that the cleanup of the previous action will be completed before the next one starts.
source share