Почему автору нужно обернуть функцию без приостановки в viewModelScope.launch? - PullRequest
2 голосов
/ 25 апреля 2020

Код A взят из примеров архитектуры проекта, вы можете увидеть его здесь .

filterItems - это нормальная функция, когда private fun filterTasks вызывает filterItems, он заключен в viewModelScope.launch.

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

Почему автору нужно обернуть функцию без приостановки с viewModelScope.launch?

код A

class TasksViewModel(
    private val tasksRepository: TasksRepository,
    private val savedStateHandle: SavedStateHandle
) : ViewModel() {

  private fun filterTasks(tasksResult: Result<List<Task>>): LiveData<List<Task>> {
        // TODO: This is a good case for liveData builder. Replace when stable.
        val result = MutableLiveData<List<Task>>()

        if (tasksResult is Success) {
            isDataLoadingError.value = false
            viewModelScope.launch {                 //Why wrapped with viewModelScope.launch
                result.value = filterItems(tasksResult.data, getSavedFilterType())
            }
        } else {
            result.value = emptyList()
            showSnackbarMessage(R.string.loading_tasks_error)
            isDataLoadingError.value = true
        }

        return result
    }

    private fun filterItems(tasks: List<Task>, filteringType: TasksFilterType): List<Task> {
        val tasksToShow = ArrayList<Task>()
        // We filter the tasks based on the requestType
        for (task in tasks) {
            when (filteringType) {
                ALL_TASKS -> tasksToShow.add(task)
                ACTIVE_TASKS -> if (task.isActive) {
                    tasksToShow.add(task)
                }
                COMPLETED_TASKS -> if (task.isCompleted) {
                    tasksToShow.add(task)
                }
            }
        }
        return tasksToShow
    }

    ...

}

1 Ответ

3 голосов
/ 25 апреля 2020

Эта функция вызывается из основного потока (в ответ на switchMap на другом LiveData), и она запускает сопрограмму с Dispatchers.Main (по умолчанию для viewModelScope), так что это фактически откладывает действие в сопрограмме до тех пор, пока все остальные текущие задачи в очереди основного потока не будут завершены.

Иногда это полезно для быстрой визуальной индикации чего-либо для одного кадра.

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

Или другая возможность: в этой сопрограмме был длительный вызов функции приостановки, она была реорганизована, и они не смогли удалить сопрограмму. Это не первый раз, когда я сталкиваюсь с ошибкой или запахом кода в примерах.

Даже если это не случайно, это тот случай, когда действительно необходимо добавить комментарий в коде объяснить это, так как это неочевидно.

...