Skip to content

Compose Rive() composable: ~370ms blank gap between first draw pass and actual bitmap content #452

@KorniienkoYehor

Description

@KorniienkoYehor

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:

  1. Pre-parse a .riv file via RiveFile.fromSource(RiveFileSource.Bytes(bytes), sharedWorker) at
    app startup (splash screen).
  2. Cache the parsed RiveFile in a singleton.
  3. 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()
      },
  )
  1. 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 — drawWithContent fires for Rive(): +1442ms
  • Compose draw pass — drawWithContent fires for sibling Icon(): +1445ms
  • onBitmapAvailable callback 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions