Следует использовать функцию расширения CoroutineScope или функцию приостановки - PullRequest
0 голосов
/ 14 декабря 2018

Я пишу приложение, используя сопрограммы (приведенный ниже код значительно упрощен).Недавно я смотрел Практические сопрограммы , и немного запутался.Оказывается, я не знаю, когда использовать функцию расширения CoroutineScope, а когда использовать функцию приостановки.

У меня есть mediator (Presenter / ViewModel / Controller / etc) который реализует CoroutineScope:

class UiMediator : CoroutineScope {
    private val lifecycleJob: Job = Job()
    override val coroutineContext = lifecycleJob + CoroutineDispatchersProvider.MAIN
    // cancel parent Job somewhere

    fun getChannel() {
        launch {
            val channel = useCase.execute()
            view.show(channel)
        }
    }
}

бизнес-логика (Interactor / UseCase):

class UseCase {
    suspend fun execute(): RssChannel = repository.getRssChannel()
}

и хранилище :

class Repository {
    suspend fun getRssChannel(): RssChannel {
        // `getAllChannels` is a suspending fun that uses `withContext(IO)`
        val channels = localStore.getAllChannels()
        if (channels.isNotEmpty()) {
            return channels[0]
        }

        // `fetchChannel` is a suspending fun that uses `suspendCancellableCoroutine`
        // `saveChannel` is a suspending fun that uses `withContext(IO)`
        return remoteStore.fetchChannel()
            .also { localStore.saveChannel(it) }
    }
}

Итак, у меня есть несколько вопросов:

  1. Должен ли я объявить Repository#getRssChannel как функцию расширения CoroutineScope (потому что она порождает новые функции приостановки: getAllChannels, fetchChannel, saveChannel)?Как я могу использовать его в UseCase тогда?
  2. Должен ли я просто обернуть Repository#getRssChannel в функцию coroutineScope, чтобы все порожденные функции приостановки были потомками последней?
  3. Или, может быть, это уже хорошо, и я ничего не должен менять.Когда тогда объявлять функцию как расширение CoroutineScope?

Ответы [ 2 ]

0 голосов
/ 14 декабря 2018

Ответ на вопрос 1:

Нет, вы должны не объявлять Repository#getRssChannel как функцию расширения CoroutineScope, потому что вы вызываете только функции приостановки, но не запускаете (launch / async) новые рабочие места.Как объяснил @Francesc, функция расширения CoroutineScope должна только запускать новые задания, но не может сразу же возвращать результат и не должна сама объявляться как suspend.

Ответ на вопрос 2:

Нет, вы должны не обернуть Repository#getRssChannel в CoroutineScope.Обтекание имеет смысл, только если вы запускаете (launch / async) новые сопрограммы в этом методе.Новые задания будут дочерними по отношению к текущему заданию, а внешний метод вернется только после завершения всех параллельных заданий.В вашем случае у вас есть последовательные вызовы других приостановленных сопрограмм, и нет необходимости в новой области видимости.

Ответ на вопрос 3:

Да, вы можете остаться со своим кодом.Если вам потребуется функциональность UiMediator#getChannel более одного раза, тогда этот метод будет кандидатом на функцию расширения для CoroutineScope.

0 голосов
/ 14 декабря 2018

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

Функция расширения CoroutineScope предназначена для запускаСценарий "забудь и забудь", он вызывается, он порождает сопрограмму и сразу же возвращается, пока задача продолжает выполняться.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...