2017-03-16 58 views
5

Zajmuję się wykorzystaniem rutynowych procedur w kontekście wątku UI Androida. Zaimplementowałem contextJob zgodnie z opisem w Coroutines Guide UI. Prace w tle są sprawdzane przez GUI i chcę je ponownie uruchomić za każdym kliknięciem (zatrzymaj aktualnie działający i uruchom go ponownie).Czy istnieje sposób ponownego użycia instancji zadania?

Ale praca raz anulowane nie mogą być ponownie wykorzystane, więc nawet tworzenie przez dzieci pracy:

val job = Job(contextJob) 

i anulowanie to nie pomaga, ponieważ musi być-przeniesiony.

Czy istnieje sposób ponownego użycia instancji zadania?

Odpowiedz

4

A Job ma bardzo prosty cykl życia według projektu. Jego stan "Completed" to final, bardzo podobny do stanu "Zniszczone" systemu Android Activity. Tak więc rodzic Job najlepiej jest skojarzyć z Activity, jak wyjaśniono w przewodniku. Powinieneś anulować zadanie nadrzędne tylko wtedy, gdy działanie zostanie zniszczone. Ponieważ zniszczonej działalności nie można ponownie wykorzystać, nigdy nie napotkasz potrzeby ponownego wykorzystania jej pracy.

Zalecanym podejściem do rozpoczęcia pracy przy każdym kliknięciu jest użycie aktorów, ponieważ pomagają uniknąć niepotrzebnej współbieżności. Przewodnik pokazuje, jak je uruchomić po każdym kliknięciu, ale nie pokazuje, jak anulować aktualnie działającą akcję.

Będziesz potrzebował świeżego wystąpienie Job w połączeniu z withContext aby blok kodu odwoływalny niezależnie od wszystkiego innego:

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 
    } 
} 

Aktor jest zawsze aktywna aż do jej pracy dominującej (dołączonym do aktywności) jest odwołany. Aktor czeka na kliknięcia i uruchamia po każdym kliknięciu action. Jednak każde wywołanie obiektu action jest pakowane do własnego bloku przy użyciu bloku , dzięki czemu można je anulować niezależnie od zadania nadrzędnego.

Pamiętaj, że kod ten z powodzeniem działa w przypadku działań, których nie można anulować lub których anulowanie zajmuje trochę czasu. Działanie może wymagać wyczyszczenia zasobów po anulowaniu, a ponieważ ten kod używa aktora, zapewnia to, że czyszczenie poprzedniej czynności zostało zakończone przed uruchomieniem następnej.