Rafael Costa
02/03/2025, 12:20 PMuiState
flow to my UI. As part of that UI State, if child slot is active, I want to provide the child instance, if it is not active I want to provide some other state data class.
The way I see it, to do this, I would combine the Value<ChildSlot<X, Y>>
with some other internal state flow.
Question is: can I convert the Value
into a StateFlow to allow me to combine it? Or is there any consequence of doing so, such as performance considerations or the like? I have a snippet that I think came from you @Arkadii Ivanov to do that conversion, I can paste on the thread.Rafael Costa
02/03/2025, 12:21 PMfun <T : Any> Value<T>.toStateFlow(): StateFlow<T> = ValueStateFlow(this)
@OptIn(ExperimentalForInheritanceCoroutinesApi::class)
private class ValueStateFlow<out T : Any>(private val source: Value<T>) : StateFlow<T> {
override val value: T
get() = source.value
override val replayCache: List<T>
get() = listOf(source.value)
override suspend fun collect(collector: FlowCollector<T>): Nothing {
val flow = MutableStateFlow(source.value)
val disposable = source.subscribe { flow.value = it }
try {
flow.collect(collector)
} finally {
disposable.cancel()
}
}
}
Rafael Costa
02/03/2025, 12:22 PM@OptIn(ExperimentalForInheritanceCoroutinesApi::class)
-- should we come up with a another way that doesn't envolve inheritance? 🤔)Arkadii Ivanov
02/03/2025, 2:04 PM@ExperimentalForInheritanceCoroutinesApi
in an end project. However, it might become an issue if used in a library, due to possible binary incompatible changes.
Another option could be:
fun <T : Any> Value<T>.asStateFlow(
scope: CoroutineScope,
started: SharingStarted = SharingStarted.Eagerly,
): StateFlow<T> =
callbackFlow {
val cancellation = subscribe { trySend(it) }
awaitClose { cancellation.cancel() }
}.stateIn(scope = scope, started = started, initialValue = value)
Rafael Costa
02/03/2025, 2:06 PMStateFlow<Instance>
instead of a Value<Configuration, Instance>
to UI. Is there any concern there? I don't see why there would be, but just wanted to confirm it 🤔Arkadii Ivanov
02/03/2025, 2:15 PMStateFlow
via StateFlow#collectAsState()
, it will use Dispatchers.Main
. So the UI will always lag one frame behind due to the re-dispatching behaviour of the Main
dispatcher. This has been actually the cause of various issues with TextField
getting out of sync with the state. So I suggest to always do something like: collectAsState(Dispatchers.Main.immediate)
.Rafael Costa
02/03/2025, 2:55 PMRafael Costa
02/03/2025, 2:55 PM