Chris Fillmore
07/19/2023, 8:54 PMFrancesc
07/19/2023, 9:16 PMIan Lake
07/19/2023, 9:23 PMMarco Pierucci
07/19/2023, 9:39 PMLaunchedEffect(textState) {
snapshotFlow { textState.value }.drop(1).debounce(1000).collect {
state.onChanged(it)
}
}
Casey Brooks
07/19/2023, 9:43 PMchannel.receiveAsFlow().collect { }
to wait for the first click to be completed before starting to process the second one. You can update a value in a StateFlow to denote success or failure, which the second one can then use to determine if the click was already handled or not. Alternatively, channel.receiveAsFlow().collectLatest { }
will cancel the first input so that the second one can start processing. There’s a lot of other power and flexibility you get for handling these kinds of different use-cases when thinking about handling code in this manner.
Here’s an example of how a VM might look doing this pattern, to help you understand the general idea:
public class MyViewModel(
private val coroutineScope: CoroutineScope,
private val api: MyApi,
) {
private val _state = MutableStateFlow(State())
private val channel = Channel<Inputs>(Channel.BUFFERED, BufferOverflow.SUSPEND)
init {
coroutineScope.launch {
channel
.receiveAsFlow()
.collect {
when (it) {
is Inputs.Submit -> {
if (_state.value.result != null) {
// ignore the click, we've already handled it
return@collect
}
val result = api.submit()
_state.update { it.copy(result = result) }
}
}
}
}
}
public fun submit() {
channel.trySend(Inputs.Submit)
}
public data class State(
val result: ApiResult? = null
)
private sealed interface Inputs {
public object Submit : Inputs
}
}
Casey Brooks
07/19/2023, 9:46 PMFrancesc
07/19/2023, 10:14 PMChris Fillmore
07/19/2023, 11:06 PMFrancesc
07/19/2023, 11:16 PMChris Fillmore
07/19/2023, 11:21 PMChris Fillmore
07/19/2023, 11:21 PM@Composable
fun <T> Debounce(
debounceMs: Long,
initialValue: T,
onChange: (T) -> Unit,
content: @Composable (onChange: (T) -> Unit) -> Unit,
) {
var value by remember { mutableStateOf(initialValue) }
LaunchedEffect(initialValue) {
snapshotFlow { value }
.drop(1)
.debounce(debounceMs)
.collect(onChange)
}
content { value = it }
}
efemoney
07/20/2023, 12:10 PM