rive-app / rive-app/rive-android
Compose Rive() composable: ~370ms blank gap between first draw pass and actual bitmap content
Nobody has claimed this yet.
- Dominant language
- Kotlin
- Stars
- 538
- Forks
- 66
- PR merge metrics
- No merged PRs in 30d
Description
When using the Compose-native Rive() composable, there is a significant delay (~370ms) between when compose first draws the Rive composable's area on screen and when Rive actually produces visible bitmap content via onBitmapAvailable.
During this gap, the composable's draw area is present in the layout but renders nothing (transparent/empty), while sibling composables (e.g. Icon()) display their content immediately on the same draw pass.
Environment:
- rive-android: 11.4.0
- Jetpack Compose
- Android 16
- Tested on physical device
Reproduction:
- Pre-parse a .riv file via RiveFile.fromSource(RiveFileSource.Bytes(bytes), sharedWorker) at
app startup (splash screen). - Cache the parsed RiveFile in a singleton.
- In a Composable, use the cached file:
val artboard = rememberArtboard(cachedFile)
val stateMachine = remember(artboard) { StateMachine.fromArtboard(artboard, null) }
val vmi = rememberViewModelInstance(cachedFile)
Rive(
file = cachedFile,
playing = true,
artboard = artboard,
stateMachine = stateMachine,
viewModelInstance = vmi,
fit = Fit.Contain(),
onBitmapAvailable = { /* log: bitmap ready */ },
modifier = Modifier.size(32.dp).drawWithContent {
// log: draw pass
drawContent()
},
)
- Place the Rive() composable alongside a standard Icon() in the same Row/Box.
Observed behavior:
Measured timestamps relative to NavBarConfigRepository.refresh() call (anchor):
Rive()composable enters composition: +1035ms- Compose draw pass —
drawWithContentfires forRive(): +1442ms - Compose draw pass —
drawWithContentfires for siblingIcon(): +1445ms onBitmapAvailablecallback fires (Rive produces actual content): +1812ms
The Rive() composable participates in the Compose draw pass at the same time as static Icon() composables (within 3ms). However, Rive's actual bitmap content doesn't appear until 370ms later.
During this 370ms gap, the Rive area on screen is blank/transparent while sibling icons are already visible. This creates a noticeable visual delay.
Expected behavior: Rive() composable should produce visible content on its first draw pass (or within 1-2 frames), consistent with how other Compose drawing primitives behave. The file is already fully parsed and cached - no I/O or parsing should be needed at render time.
Context:
- The .riv file is small (967 bytes), pre-parsed via shared CommandQueue worker ~800ms before the
composable enters composition. Parse itself takes ~70ms. - rememberArtboard() and rememberViewModelInstance() are called before Rive() in the same
composition. - playing = true is set, so the state machine should advance immediately.
- The delay is consistent across cold starts (~350-400ms each time).
- This is not a TextureView surface init issue — we specifically migrated from
AndroidView(RiveAnimationView) (which had ~500ms TextureView surface delay) to Compose-native
Rive() to avoid that. The Compose path is faster but still has this internal gap.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing the Compose-native Rive() path from composition and its draw pass through onBitmapAvailable, using the supplied rememberArtboard, StateMachine, and rememberViewModelInstance reproduction. Compare the first draw timing with bitmap readiness on a physical Android device. Done means visible Rive content appears on the first draw or within 1–2 frames, without the reported blank gap.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, kotlin
- Domain
- mobile, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100