java.lang.IllegalStateException: Composition cannot be performed while another composition is in progress on ComposeView.setContent
0 reputation · 03 Sept 2021, 08:08 UTC
0 reputation · 03 Sept 2021, 08:08 UTC
Determine whether invoking ComposeView.setContent from a non-UI thread is the direct cause of intermittent IllegalStateException failures, and whether the exception reflects a hard composition concurrency limit rather than a transient lifecycle race.
The exact exception string may change between Compose runtime releases, so message matching is not a stable contract. ComposerImpl throws the error when a new composition attempt begins before the previous composition scope exits, but the public API does not clearly state whether nested setContent calls on the same ComposeView are serialized, rejected, or left undefined.
ComposeView.setContent safely handle sequential calls from the main thread while a prior composition is still inflight?ComposeView composition?Yes. Invoking ComposeView.setContent from a background thread is the primary cause of the intermittent IllegalStateException you see. The exception is a hard guard that the Compose runtime uses to ensure only one composition can be active per ComposerImpl instance. When a second composition starts before the first one has finished, the runtime throws the exception regardless of whether the call originates from the UI thread or elsewhere. In practice, off‑thread calls trigger a thread‑affinity violation that surfaces as the same exception.
ComposerImpl.startComposition() sets a flag that is cleared only when the composition exits. Re‑entering before that flag is cleared causes IllegalStateException.ComposeView.setContent is documented to run on the UI thread. A background thread bypasses the internal checks that would otherwise schedule the composition on the main looper.setContent calls in runOnUiThread { … } or use view.post { … }.
runOnUiThread {
composeView.setContent { MyComposable() }
}
Log.i("Compose", "Runtime: ${androidx.compose.runtime.version}")
Compare against the latest stable release; older 1.x versions were more tolerant of off‑thread calls, but 2.0+ enforce the rule strictly.
var compositionDepth = 0
composeView.setContent {
compositionDepth++
// content
compositionDepth--
}
If compositionDepth ever exceeds 1, you have overlapping compositions.
setContent twice on the main thread while the first composition is still inflight (e.g., by introducing a delay inside the composable). The exception should not occur; the runtime will queue the second call until the first finishes.
ComposeView is attached before calling setContent. If you call it during onCreateView before onViewCreated, the view might not have a valid window token, which can also lead to composition errors.
If you still encounter the exception after enforcing UI‑thread calls, please provide:
setContent during an ongoing composition.The exception is a hard concurrency guard, not a transient race. The safest path is to keep setContent on the main thread and let Compose handle serialization of sequential calls. If you need to trigger recompositions from background work, post the new content to the UI thread instead of invoking setContent directly from that thread.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.