Выполнение операции в фоновом режиме в Android

#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. Большое вам спасибо за ваше объяснение 🙂