My coroutine education continues...any ideas on wh...
# coroutines
d
My coroutine education continues...any ideas on why this code prints nothing:
Copy code
refreshScope = CoroutineScope(Job())
                refreshScope.launch(Dispatchers.Default) {
                    println("Clicked Refresh button pntln.")
                }
but this produces text?
Copy code
refreshScope = CoroutineScope(Job())
                refreshScope.launch(<http://Dispatchers.IO|Dispatchers.IO>) {
                    println("Clicked Refresh button pntln.")
                }
The only difference is the Dispatcher (IO works, Default doesn't). The issue is somewhere else in my code, I expect, and there's far too much to include; both code snippets work in a vacuum. I'm just hoping for a direction to start looking.
j
I can't reproduce it in isolation: https://pl.kotl.in/oXBG_tmId (note that this playground suffers from the same problem as your earlier post, but for some reason it works ok nonetheless). Maybe it has something to do with other things around this call, it might be helpful to share a bit more (at least the full listener of the button maybe, or its relevant parts).
Note that you shouldn't create a scope in each listener call, by the way. A single scope should be used, and cancelled when appropriate
n
Is this like your earlier question where you want to know why one manages to run before the process dies when the other doesn't quite get there?
j
I think it's part of the same investigation yes. But the end of the process is kinda irrelevant in the real code because it's part of a listener AFAIU (it is relevant in my playground, though, which cannot prove anything tbh)
n
If your process isn't dying then I suspect you've clogged all of `Dispatcher.Default`'s threads with blocking calls. This is fine:
Copy code
GlobalScope.launch(Dispatchers.Default) { someStateFlow.collect { yield(1000) } }
This is not:
Copy code
GlobalScope.launch(Dispatchers.Default) { someStateFlow.collect { Thread.sleep(1000) } }
d
Sorry, was unexpectedly afk. Clogging all of the other dispatchers was all I could think of, too. It's a compose application with a fair amount of code, I'm not sure how to share just relevant bits.
and yet, when it's running, there's only one thread running under Default
here's the full method
Copy code
@Composable
private fun AppState.refreshButton() {
    val refreshScope by remember { mutableStateOf(CoroutineScope(Job())) }

    TooltipArea(
        tooltip = { SmolTooltipText(text = "Refresh modlist & VRAM impact") }
    ) {
        Button(
            onClick = {
                Timber.d { "test." }
                refreshScope.launch(Dispatchers.Default) {
                    Timber.d { "Clicked Refresh button." }
//                    reloadMods()
                }
            },
            modifier = Modifier.padding(start = 16.dp)
        ) {
            Icon(
                painter = painterResource("refresh.svg"),
                contentDescription = "Refresh",
                tint = SmolTheme.dimmedIconColor()
            )
        }
    }
}
When you click the button, "test." prints, but the
launch
inside the click handler doesn't fire
n
I haven't done anything with compose, does modifying remembered mutable state recreate the button? Wondering if maybe setting refreshScope is invalidating the button causing it to be recreated so the remembered scope is cancelled before it has a chance to print? or not given the edited code.
d
that's exactly what happened 🙂 but it was happening before i added the things that created the loop; they were just there to try and debug it
huh, with the edited code, it fires the first time but not after that...
ah
Copy code
refreshScope.launch(Dispatchers.Default) {
    Timber.d { "Clicked Refresh button." }
    reloadMods()
    Timber.d { "Finished reloading mods 2." }
}
The second debug line is never hit
I believe I figured it out
I am watching multiple folders on the filesystem using WatchService
on the Defaut dispatcher
They run with a
while(isActive)
loop
but have no
delay
and no
yield
Thanks to Joffrey's answer on a previous question, I realized that I needed to put a yield in the loop, and that fixed it
🆒 1
It's not the best solution, but as far as figuring out the culprit, it worked
👍 1
With a few more sensible changes (using DisposibleEffect, changing some dispatchers), things are humming along and much more performant than before!
Learned a lot today, thank you
j
Sorry I was afk for a while as well, super glad you found the reason eventually!