parth
10/13/2021, 2:44 PMMutableStateFlow
. Looks something like this:
fun whatever() {
viewModelScope.launch {
inputFlow
.map {...}
.collect { value ->
mutableStateFlow.value = value
}
}
}
(Assume that I need to push other values into the MSF
outside this collect
block)
One issue I’ve run into with the above construction is that when the observer of the MSF
cancels collection (e.g. the Fragment observing the ViewModel falls off the screen), it doesn’t cancel this intermediate collection…this makes absolute sense — that cancellation signal is not being propagated upstream!
So digging into the stateIn
sources, I’ve come up with what I think is a way to push the cancellation “upstream” — can y’all give thoughts/comments/suggestions on the following approach?
fun <T> Flow<T>.stateInto(downstream: MutableStateFlow<T>, scope: CoroutineScope) {
val upstream = this
scope.launch {
downstream.subscriptionCount
.mapLatest { count -> //this is a simplified version of [StartedWhileSubscribed#command]
if (count > 0) true
else {
delay(800.milliseconds)
false
}
}
.dropWhile { active -> !active }
.distinctUntilChanged()
.collectLatest { active ->
when (active) {
true -> upstream.collect(downstream) //will be cancelled upon new emission
false -> Unit /*just cancel and do nothing*/
}
}
}
}
darkmoon_uk
10/15/2021, 1:36 AMdarkmoon_uk
10/15/2021, 1:37 AMdarkmoon_uk
10/15/2021, 1:38 AMmutableStateFlow
is.darkmoon_uk
10/15/2021, 1:38 AMdarkmoon_uk
10/15/2021, 1:38 AM.value =
?darkmoon_uk
10/15/2021, 1:38 AMinputFlow
darkmoon_uk
10/15/2021, 1:39 AMdarkmoon_uk
10/15/2021, 1:39 AMmutableStateFlow
no longer mutable, but instead an immutable outputFlow
darkmoon_uk
10/15/2021, 1:41 AMval outputFlow: Flow<SomeType> = inputFlow.map { ... } // What about the other inputs?
darkmoon_uk
10/15/2021, 1:41 AMmerge
or combine
these together.darkmoon_uk
10/15/2021, 1:42 AMparth
10/15/2021, 1:58 AMFlow.stateIn(...)
darkmoon_uk
10/15/2021, 2:21 AMNick Allen
10/19/2021, 4:04 AMprivate val nonInputStateFlow = MutableStateFlow<ValueType>
val outputFlow = merge(inputFlow.map {...}, nonInputStateFlow)
fun otherMethod1(value: Value) {
otherMethodFlow.tryEmit(value)
}
fun otherMethod2(somethingElse: SomethingElse) {
otherMethodFlow.tryEmit(calculateValue(somethingElse))
}