Как использовать объединенный результат 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.