Как использовать объединенный результат Kotlin Flows в модели просмотра из нескольких вариантов использования / взаимодействий?

Задний план

Я пытаюсь реализовать шаблон чистой архитектуры в стиле MVVM с репозиториями и вариантами использования / взаимодействиями. Я хотел бы использовать Kotlin Flows для вариантов использования / взаимодействия. Все варианты использования имеют одинаковую настройку, и результат помещается в запечатанный класс.

Обертка ответа:

sealed class Response<out T> {
    object Loading : Response<Nothing>()
    data class Success<T>(val data: T? = null) : Response<T>()
    data class Error(val error: ErrorEntity? = null) : Response<Nothing>()
    data class Empty(val msg: Int = R.string.empty_string) : Response<Nothing>()
}

все варианты использования / взаимодействия реализуют:

interface UseCase<T, Params> {
    fun execute(params: Params? = null) : Flow<Response<T>>
}

Проблема

В моем примере мне нужно использовать результат класса GetFbUserUseCase внутри результата GetAllUsersUseCase. Оба они генерируют состояния загрузки, ошибки и результата, которые я хотел бы напрямую передать пользовательскому интерфейсу.

Пример кода

class TaskEditViewModel(
    private val getCurrentFbUserUseCase: GetFbUserUseCase,
    private val getAllUsersUseCase: GetAllUsersUseCase
) : ViewModel() {

private val _pageState = MutableLiveData<Response<*>>()
val pageState: LiveData<Response<*>>
    get() = _pageState

fun getUsers() {
    viewModelScope.launch {

        // get current user ID from GetFbUserUseCase.
        val firebaseUser: Flow<Response<FirebaseUser?>> = getCurrentFbUserUseCase.execute()
        // get all users from GetAllUsersUseCase. 
        val userList: Flow<Response<List<User>>> = getAllUsersUseCase.execute()

        // somehow combine both results??
        merge(firebaseUser, userList).collect { response ->

            // delegate the combined Loading, Error states to the UI ?
            _pageState.value = response

            // only handle the Success state in the viewmodel? 
            when (response) {
                is Response.Success<*> -> {
                    // get current user ID from GetFbUserUseCase

                    // apply filtering on the result of `GetAllUsersUseCase` with the result
                    // from `GetFbUserUseCase` and show different UI accordingly
                    if (response.data.filterNot { it.userId == currentUser.userId }.isEmpty()) {
                        // notify liveData to show current user
                    } else {
                        // notify liveData to show complete user list
                    }
                }
            }
        }
    }
}

Вопрос:

согласно: Потоки Kotlin. Существует несколько вариантов составления и сглаживания нескольких потоков. Какой из них лучше всего подходит для моей проблемы и как я могу это реализовать?

1 ответ

Я вижу, комбайн решает твою проблему.

Вот как совместить эти два потока

firebaseUser.combine(userList).collect { fbuser, userlist -> 
  //combine the results and set the livedata here
  someFunThatSetsLiveData(fbuser, userlist)
}    

Каждый раз, когда один из этих потоков генерирует новый результат, вызывается someFunThatSetsLiveData.

Другие вопросы по тегам