dave08
04/25/2023, 12:11 PMStateFlow from a callback (the first state is queried and the callback is just to listen for changes to that first state - but I need to unregister from the callback when the flow is cancelled...)? I know there's stateIn, but I'd rather do it w/o having to pass a coroutine context there...CLOVIS
04/25/2023, 12:13 PMstateIn . It's not possible to do it without stateIn , because a callback is cold, and a StateFlow is hot (= it maintains its own state even when no one is looking at it). That means it has to run somewhere, which is in a coroutine (thus it must have a CoroutineScope)dave08
04/25/2023, 12:17 PMMutableStateFlow and manage the registration to the callback there... when it's run I would return the StateFlow, but then I'd have a problem with cancellation not unregistering.dave08
04/25/2023, 12:17 PMdave08
04/25/2023, 12:18 PMcoroutineScope { launch { } }, to run it on the coroutine scope of the caller function (this function can be suspend)dave08
04/25/2023, 12:19 PMCLOVIS
04/25/2023, 12:19 PMdave08
04/25/2023, 12:20 PMdave08
04/25/2023, 12:20 PMdave08
04/25/2023, 12:21 PMdave08
04/25/2023, 12:22 PMCLOVIS
04/25/2023, 12:22 PMonStart { emit("Your default value") } on any cold flow (it will still be a cold flow, but it will have that first value instantly available) → https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/on-start.htmldave08
04/25/2023, 12:23 PMCLOVIS
04/25/2023, 12:23 PMCLOVIS
04/25/2023, 12:23 PMfun yourFlow() = flow {
…
}.onStart { … }dave08
04/25/2023, 12:25 PMsomeFlow: Flow<X> as a parameter, which doesn't tell the implementer of that flow that a first value is required... it's like using a regular List as an input parameter to a function when you mean a NonEmptyList...dave08
04/25/2023, 12:26 PMCLOVIS
04/25/2023, 12:26 PMStateFlow ? In your version, it is not stateful, as its state only exists while the call to the other function is active, after which it becomes frozen foreverdave08
04/25/2023, 12:29 PMfun provider() = MutableStateFlow<X>().apply {
state = X()
// register listener to return X updates
this.asStateFlow()
}
suspend fun receiver(states: StateFlow<X>) {
// I have an assurance that a first value is available already
states.collect {
//// process...
}
}
// usage:
receiver(provider())
// In tests I'm forced to make a provider with a first value too...CLOVIS
04/25/2023, 12:31 PMCLOVIS
04/25/2023, 12:34 PMdave08
04/25/2023, 12:35 PMdave08
04/25/2023, 12:35 PMCLOVIS
04/25/2023, 12:37 PMCLOVIS
04/25/2023, 12:37 PMonStart and adds some documentationdave08
04/25/2023, 12:38 PMdata class NonEmptyFlow<T>(val firstState: T, val flow: Flow<T>) 🤒CLOVIS
04/25/2023, 12:39 PM@JvmInline
value class NonEmptyFlow<T> internal constructor(private val flow: Flow<T>) : Flow<T> by flow
fun <T> Flow<T>.withDefault(block: suspend () -> T) = this
.onStart { emit(block()) }
.let { NonEmptyFlow(it) }CLOVIS
04/25/2023, 12:42 PMflow.withDefault { 1 }.withDefault { 2 }.toList() , it will print [2, 1, <everything else>] , so "default" is probably not the right namedave08
04/25/2023, 12:43 PMby flow , so a value class wouldn't help?CLOVIS
04/25/2023, 12:44 PMFlow<T> , then yes, for sureCLOVIS
04/25/2023, 12:44 PMdave08
04/25/2023, 12:45 PMgildor
04/25/2023, 3:41 PMdave08
04/25/2023, 3:47 PMgildor
04/25/2023, 3:49 PMCLOVIS
04/25/2023, 3:51 PMstateIn(GlobalScope) because you lose all control over the running operation / memory freeinggildor
04/25/2023, 3:52 PMgildor
04/25/2023, 3:53 PMgildor
04/25/2023, 3:55 PMgildor
04/25/2023, 3:57 PM