Каков срок службы coroutineScope в Kotlin? - PullRequest
0 голосов
/ 20 апреля 2020

Код A взят из примеров архитектуры проекта в https://github.com/android/architecture-samples

1: я не знаю, нужно ли просто обернуть функцию activateTask(task: Task) в runBlocking как код B. Я боюсь, что activateTask(task: Task), возможно, не будет запущен, если объект DefaultTasksRepository быстро уничтожается.

2: Обычно я запускаю сопрограммы в ViewModel.viewModelScope, я не знаю, ViewModel.viewModelScope будет уничтожено, когда я закончу sh приложение, и будут ли уничтожены сопрограммы, работающие в ViewModel.viewModelScope. Если это так, я думаю, что это будет плохо, некоторые сопрограммы, такие как запись данных на удаленный сервер, будут отменены.

3: И еще, функция activateTask в коде A является функцией сопрограмм, она может напрямую вызывать другую функцию сопрограмм, поэтому я думаю, что код A + правильный, верно?

код A

import kotlinx.coroutines.coroutineScope
...

class DefaultTasksRepository(
    private val tasksRemoteDataSource: TasksDataSource,
    private val tasksLocalDataSource: TasksDataSource,
    private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
) : TasksRepository {
   ...

   override suspend fun activateTask(task: Task) = withContext<Unit>(ioDispatcher) {
        coroutineScope {
            launch { tasksRemoteDataSource.activateTask(task) }
            launch { tasksLocalDataSource.activateTask(task) }
        }
    }

   override suspend fun clearCompletedTasks() {
        coroutineScope {
            launch { tasksRemoteDataSource.clearCompletedTasks() }
            launch { tasksLocalDataSource.clearCompletedTasks() }
        }
    }
   ...
}

код A +

import kotlinx.coroutines.coroutineScope
...

class DefaultTasksRepository(
    private val tasksRemoteDataSource: TasksDataSource,
    private val tasksLocalDataSource: TasksDataSource,
    private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
) : TasksRepository {
   ...

   override suspend fun activateTask(task: Task) = withContext<Unit>(ioDispatcher) {
        tasksRemoteDataSource.activateTask(task) 
        tasksLocalDataSource.activateTask(task)         
    }

   override suspend fun clearCompletedTasks() {            
        tasksRemoteDataSource.clearCompletedTasks() 
        tasksLocalDataSource.clearCompletedTasks()             
   }
   ...
}

код B

fun main() = runBlocking { 
    launch { 
      delay(1000L)
      println("World!")
    }
    println("Hello,")
}

1 Ответ

1 голос
/ 20 апреля 2020
  1. Вы не должны использовать runBlocking в любом приложении сопрограммы, оно блокирует поток.

    Если вы действительно хотите сделать activateTask неотменяемым, существует фабричная реализация NonCancellable уже в stdlib

    И вы не должны использовать оболочку coroutineScope внутри withContext, так как вновь созданный CoroutineScope вместе с новым заданием уже передан как получатель в withContext.

    Реализуйте свою activTask следующим образом:

override suspend fun activateTask(task: Task) = withContext<Unit>(ioDispatcher + NonCancellable) {
    launch { tasksRemoteDataSource.activateTask(task) }
    launch { tasksLocalDataSource.activateTask(task) }
}

Таким образом, он будет вызываться в IODispatcher, но не будет отменен, так как элемент Job результирующего контекста не обеспечить функциональность, чтобы отменить его.

ViewModelScope работает до тех пор, пока ваше приложение не будет уничтожено, дополнительная информация и диаграмма жизненного цикла здесь . Если вы хотите выполнить несколько очень важных задач, используйте других диспетчеров.

Да, код A + полностью правильный

PS: Вы не должны реализовывать runBlocking в приложении сопрограммы, его реализацией по умолчанию является просто событие l oop.

runBlocking - это способ соединить синхронный и асинхронный код

Лучшая реализация основной функции должна выглядеть следующим образом:

suspend fun main() = coroutineScope {
    // code here
}

Она работает на CommonPool, и если она приостанавливается, другая сопрограмма может повторно использовать тот же поток.

...