У меня есть MediatorLiveData, который использует три источника LiveData. Когда какой-либо из них выдает новое значение, и у меня есть хотя бы одно из них, я использую три значения для создания вывода для пользовательского интерфейса.
Два источника — это пользовательские настройки для сортировки и фильтрации списка, а третий — данные списка, извлеченные из потока базы данных Room.
Это выглядит примерно так:
val thingsLiveData: LiveData<List<Thing>> = object: MediatorLiveData<List<Thing>>() {
var isSettingA: Boolean = true
var settingB: MySortingEnum = MySortingEnum.Alphabetical
var data: List<Thing>? = null
init {
addSource(myRepo.thingsFlow.asLiveData()) {
data = it
dataToValue()
}
addSource(settingALiveData) {
isSettingA= it
dataToValue()
}
addSource(settingBLiveData) {
settingB= it
dataToValue()
}
}
private fun dataToValue() {
data?.let { data ->
viewModelScope.launch {
val uiList = withContext(Dispatchers.Default) {
produceUiList(data, isSettingA, settingB)
}
value = listItems
}
}
}
}
Я ищу чистый способ преобразовать это в SharedFlow, желательно без каких-либо @ExperimentalCoroutinesApi
. Единственная функция построителя SharedFlow, с которой я столкнулся, — это callbackFlow
, которая неприменима. Вы собираетесь использовать flow { ... }.asSharedFlow(...)
в большинстве случаев, и если да, то как это будет выглядеть здесь?
Две настройки LiveData я тоже планирую перенести на потоки.
@ IR42 Имеет ли значение, являются ли источники горячими SharedFlows или холодными потоками при использовании combine
? Я не совсем понимаю, какое поведение следует ожидать при работе с горячими потоками, поскольку большая часть документации по функциям, по-видимому, все еще написана с предположением, что потоки всегда холодные.
@Tenfour04 Tenfour04 Я думаю, что этот ответ тесно связан с вашим вопросом stackoverflow.com/a/65645981/1495230
@Deinlandel Да, вроде того. Это мой собственный ответ. Я понимаю это лучше, чем когда писал это. Холодные потоки с источниками горячего потока просто пропускают выбросы, поступающие до того, как они собираются.
Исходные потоки можно комбинировать с помощью Combine(), которая создает холодный поток, который после сбора начнет собирать исходные потоки, которые могут быть горячими или холодными.
Первоначально я думал, что я должен что-то упустить и что должен быть какой-то способ напрямую объединить горячие потоки в объединенный горячий поток. Но я понял, что имеет смысл, что операторы должны возвращать только холодные потоки и оставлять на ваше усмотрение преобразование обратно в горячий поток, если это то, что вам нужно.
Во многих случаях, таких как мой, совершенно нормально оставить его холодным. Я собираю этот поток только из одного места в своем пользовательском интерфейсе, поэтому не имеет значения, что он начинает объединять источники только тогда, когда он собран. Горячие потоки-источники не заботятся о том, собирает ли их что-то в данный момент или нет... они просто продолжают излучать, несмотря ни на что.
Если бы я собирал этот поток из нескольких мест или несколько раз, то может иметь смысл использовать shareIn
на объединенном потоке, чтобы сделать его горячим, что позволит избежать лишней работы по объединению источников. Потенциальным недостатком будет то, что он будет объединять эти источники, даже если ничего не собирается, что будет напрасной работой.
val thingsFlow: Flow<List<Thing>> = combine(
myRepo.thingsFlow,
settingALiveData.asFlow(),
settingBLiveData.asFlow()
) { data, isSettingA, settingB -> produceUiList(data, isSettingA, settingB) }
// where produceUiList is now a suspend function that wraps
// blocking code using withContext
я думаю, вы можете использовать функцию Combine в качестве замены MediatorLiveData