Is there a way to reuse a job instance?

I am exploring the use of shared routines in the context of the Android UI thread. I implemented contextJob as described in the Coroutines manual interface . Background work is viewed from the graphical interface, and I want to restart it each time I click (stop the current launch and restart it).

But a job that has been canceled cannot be reused, even when creating a child job:

  val job = Job(contextJob) 

and canceling it does not help, because it must be reassigned.

Is there a way to reuse a job instance?

+5
source share
1 answer

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.

+4
source

Source: https://habr.com/ru/post/1265542/


All Articles