UI not updating after StateFlow emit while window ...
# compose-desktop
m
UI not updating after StateFlow emit while window is inactive (Compose Desktop)
Hey everyone 👋 I noticed an issue in my Compose Desktop app related to UI not updating when the window loses focus. Here’s the situation: • I have a
ViewModel
with a
MutableStateFlow
that updates UI after a delay. • When the app is loading for 5 seconds, I switch to another window (so my Compose Desktop app loses focus). • After 5 seconds (in logs), the
UiState
updates successfully — I can see:
Copy code
MainViewModel: Initializing...
MainViewModel: Loading...
MainViewModel: Loaded!
MainViewModel: Context changed!
MainViewModel: Updating message...
MainViewModel: Message set!
MainViewModel: Done!
• But when I return to the app window, it still shows the old loading UI. • The new state only appears after I resize the window — then the UI suddenly updates and shows the new message. So, the
StateFlow
value is updating, but the Compose UI doesn’t recompose until I manually trigger a redraw (e.g., window resize or focus regain).
Copy code
class MainViewModel : ViewModel() {

    private val _uiState = MutableStateFlow(MainUiState())
    val uiState= _uiState.asStateFlow()

    init {
        println("MainViewModel: Initializing...")
        viewModelScope.launch {
            println("MainViewModel: Loading...")
            delay(5000)
            println("MainViewModel: Loaded!")
            withContext(Dispatchers.Main) {
                println("MainViewModel: Context changed!")
                println("MainViewModel: Updating message...")
                _uiState.update {
                    MainUiState(
                        isLoading = false,
                        message = "Hello from ViewModel 👋"
                    )
                }
                println("MainViewModel: Message set!")
            }
            println("MainViewModel: Done!")
        }
    }
}
data class MainUiState(
    val isLoading: Boolean = true,
    val message: String? = null
)

@Composable
fun MainScreen() {
    val viewModel = viewModel<MainViewModel>()
    val uiState by viewModel.uiState.collectAsState()

    Box(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        contentAlignment = Alignment.Center
    ) {
        if (uiState.isLoading) {
            CircularProgressIndicator()
        } else {
            Text(
                text = uiState.message ?: "No message",
            )
        }
    }
}
Copy code
kotlin = "2.2.21"
composeMultiplatform = "1.9.2"
androidx-lifecycle = "2.9.5"

androidx-lifecycle-viewmodel-compose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" }
androidx-lifecycle-runtime-compose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose", version.ref = "androidx-lifecycle" }
macOS 26.0
g
I didn't deep dive too much, but try collectAsStateWithLifecycle() It must resubscribe on resume of lifeycle
m
this not work
Copy code
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
this work it
Copy code
val uiState by viewModel.uiState.collectAsStateWithLifecycle(minActiveState = Lifecycle.State.RESUMED)
g
It's still quite strange,but I'm not sure about onStop semantics on JVM
m
yes it very strange. if we compose multiplatform android, ios, desktop so what use collectAsState or collectAsStateWithLifecycle with resume it collectasstate in desktop not work
should i create issue on github or youtrack
g
I believe it's fine for collectAsState
So in general you always should use with lifecycle
I think you should use compose multiplatform issue tracker https://youtrack.jetbrains.com/newIssue?project=CMP
m
i feel it issue because normal collectAsStateWithLifecycle also same behaviour collectAsState. but we use collectAsStateWithLifecycle with resume it works but what other platform android, ios.
g
With lifecycle has not the same behavior
But I agree. I would expect it to work for desktop in this case
m
yes
g
I don't think title is correct StateFlow does emit. You can verify if subscribe from outside of UI code The issues is that compose is not recomposed with current state flow value
m
so what should be issue title
ok ok i change it
again check it
@gildor hii if your system same issue. comment out os and version. it will helpful thank you
g
I can try, if you share a sample project
m
in comment desktop2.zip
g
It works fine for me, on macOS 26