Is there a timer I can run that would run in the U...
# compose-desktop
y
Is there a timer I can run that would run in the UI thread only (equivalent to JS / settimeout)? Or can I post a message to the UI message queue? How do I do that? I am just worried that modifying the state from another thread is never a good idea in UI development.
b
launch(Dispatchers.Main) { delay(ms); doStuff() } ?
i
launch(Dispatchers.Main) { delay(ms); doStuff() }
Yes,
GlobalScope.launch(Dispatchers.Main) { delay(ms); doStuff() }
, if your action should outlive the current Composable. If your delayed action makes sense only in the current Composable, you can use `rememberCoroutineScope`:
Copy code
val scope = rememberCoroutineScope()
Button(
    onClick = {
        scope.launch {
            delay(2000)
            ...
        }
    }
) {
}
When Composable is disposed, the scope will be cancelled, and action will never be performed.
y
Thank you very much. I will try this.
j
Is
Dispatchers.Main
going to run on the UI thread? I haven't verified, but I wouldn't have expected that it would. Compose applies its UI operations on the AWT event thread. To post an operation to this thread, you can use SwingUtilities.invokeLater() or SwingUtilities.invokeAndWait() Depending on how you model your state, if you are using the functions (
mutableStateOf
,
stateListOf
, etc) that Compose provides SnapshotState.kt, you are generally safe to mutate from any thread.
i
Is 
Dispatchers.Main
 going to run on the UI thread?
If we only use Compose for Desktop, then yes -
Dispatchers.Main
will use UI thread. But you are right, the safer way is not to use
Dispatchers.Main
and use
Dispatchers.Swing
instead. Any third-party library can override
Dispatcher.Main
if it depends on the other coroutine dispatcher (for example, on
kotlinx-coroutines-javafx
).
you are generally safe to mutate from any thread.
👍 yes, it should be safe. But there are a case, when we want to change multiple states which should be changed synchronously with UI (for example,
isError
and
errorMessage
). If recomposition happens between changes of two states we can see "glitches". We can combine these states as one single state, or change them in UI thread.
y
my "timer" modifies multiple state variables and can also end the timer itself, while I have a button onClick even handler that can end the timer... having the timer run in the UI thread would guarantee that the onClick even is not processed at the same time. Like I was suggesting in JS with setTimeout, this is what happens and it makes the code a lot easier to write and reason about because it is essentially thread safe from that point of view
j
If you need to modify multiple states at the same time, you could combine them but it is unfortunate for such constraints to impact your data model design. A more flexible solution might to work in snapshots, which are effectively like database transactions, allowing you to see consistent states of the world and make changes atomically. See: https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/[…]/androidx/compose/runtime/snapshots/Snapshot.kt?q=snapshot.kt