#android #multithreading #kotlin #background
Вопрос:
В проекте Android, написанном на Kotlin, у меня есть структура данных, над которой я хочу выполнить некоторые операции в одном потоке, потому что ни один из них не предназначен для потокобезопасности, и порядок операций, выполняемых над ним, важен. Я не хочу, чтобы этот поток был основным потоком, потому что операции выполняются медленно.
Я пробовал создавать свой ThreadContext несколькими способами:
val threadContext = newFixedThreadPoolContext(1, "Background")
val threadContext = newSingleThreadContext("BioStackContext")
val threadContext = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
и каждый раз, когда я вызываю run на нем, я получаю IsCurrent == true:
threadContext.run {
val isCurrent = Looper.getMainLooper().isCurrentThread()
Однако, если я вызову блокировку запуска, я получу IsCurrent == false:
runBlocking(threadContext) {
val isCurrent = Looper.getMainLooper().isCurrentThread()
Как я могу запустить его без блокировки в фоновом режиме?
Комментарии:
1. Почему не сопрограммы?
Ответ №1:
Вызываемая run
вами функция-это функция области видимости Kotlin, которая не имеет ничего общего с сопрограммами. Это функция, которую можно вызвать для чего угодно, чтобы создать лямбду с ней в качестве получателя, и код встроен, поэтому он запускается немедленно в текущем потоке.
Чтобы правильно использовать диспетчер, вам нужна сопрограмма, которую вы используете для launch
сопрограммы, и в этой сопрограмме вы можете withContext(threadContext)
выполнять свою фоновую работу. На Android вам редко понадобится создавать собственную сопрограмму, поскольку действия, фрагменты и модели просмотра предоставляют вам ту, которая уже привязана к их жизненным циклам.
Если бы вы выполняли эту задачу в Действии или Фрагменте, это выглядело бы так:
lifecycleScope.launch {
val result = withContext(threadContext) { // we are in the single thread context in this block
calculateSomethingTimeConsumingWithObjectOnlyWorkedWithOnMySingleThreadContext()
}
// Back on main thread:
updateUI(result)
}
В модели представления вы бы использовали viewModelScope
вместо lifecycleScope
.
Комментарии:
1. Большое вам спасибо за ваше объяснение 🙂