Intereting Posts
Как получить доступ к Mono <T> При обработке исключения с помощью onErrorMap ()? Кинжал не создает компонент для androidTest Используя Flux вместо цикла for, какие-либо преимущества? Широковещательный приемник onReceive () не вызывается Kotlin: как создать 2D-массив типа String Как я могу получить перечисление Kotlin одинакового поведения как cpp Настройте проект Spring Boot с Kotlin База данных андроида Kotlin: не может использовать java.lang.String для android.database.Cursor Котлин «Смарт-литье невозможно, потому что к этому моменту собственность могла быть изменена» Общие ограничения на один конструктор Возможно ли реализовать индивидуальное деструктурирование для не-класса данных в Котлин? RecyclerView itemClickListener в Котлине Kotlin: Видимость статического вложенного класса Java, объявленного внутри невидимого класса Оператор as и ClassCastException Как использовать настраиваемый сеттер в корпусе конструктора класса Kotlin

Есть ли способ повторно использовать экземпляр задания?

Я изучаю использование совместных подпрограмм в контексте потока пользовательского интерфейса Android. Я реализовал contextJob как описано в интерфейсе руководства contextJob . Фоновая работа просматривается из графического интерфейса, и я хочу перезапустить его при каждом нажатии (остановить текущий запуск и снова запустить его).

Но задание, которое было отменено, нельзя использовать повторно, даже создавая работу ребенка:

  val job = Job(contextJob) 

и отмена его не помогает, потому что она должна быть переназначена.

Есть ли способ повторно использовать экземпляр задания?

Работа имеет очень простой жизненный цикл по дизайну. Его состояние «Завершено» окончательно , очень похоже на «Уничтоженное» состояние Android- Activity . Таким образом, родительский Job лучше всего связать с Activity , как описано в руководстве. Вы должны отменить родительскую работу, если и только если действие уничтожено. Поскольку разрушенное действие нельзя использовать повторно, вы никогда не столкнетесь с необходимостью повторного использования его работы.

Рекомендуемый подход к началу работы над каждым кликом – использование актеров, потому что они помогают избежать ненужного параллелизма. В руководстве показано, как запустить их при каждом щелчке, но не показывает, как отменить текущее действие.

Вам понадобится новый экземпляр Job в сочетании с withContext чтобы блокировать код кода отдельно от всего остального:

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

Актер всегда активен до тех пор, пока его родительское задание (прикрепленное к активности) не будет отменено. Актер ждет кликов и запускает action для каждого клика. Тем не менее, каждый вызов action withContext в его собственную Job с использованием блока withContext , поэтому его можно отменить отдельно от родительского задания.

Обратите внимание, что этот код изящно работает для действий, которые не подлежат аннулированию или просто требуется некоторое время для отмены. Действие может потребоваться очистить ресурсы, когда оно отменено, и, поскольку этот код использует актера, он гарантирует, что очистка предыдущего действия будет завершена до того, как будет запущена следующая.