Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Android: settled RiveViews keep drawing every vsync (render loop only stops when paused)

Open
#424 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
35/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
kotlin, react-native
Domain
mobile-dev

Research direction

Start in RiveReactNativeView.kt, at the Choreographer frame callback where the paused and needsRedraw skip check sits above worker.draw(...). Then trace how settled gets set from CommandQueue.settledFlow and StateMachineSettlingStore, and where unsettle would need to be called. Done means a settled view stops calling draw while idle, confirmed by frame counts in dumpsys gfxinfo. The second half, wiring to the non-deprecated settle API, needs a maintainer decision on the public surface first.

Written by the indexing model from the issue text.

Description

On Android (src/new, rive-android 11.12.1, @rive-app/react-native 0.5.5), the Choreographer render loop in RiveReactNativeView.kt calls worker.draw(...) on every frame unless the view is paused:

if (paused && !needsRedraw) { … return }
…
if (!paused && !settled) worker.advanceStateMachine(sm, deltaTime)
worker.draw(art, sm, rs, activeFit, …)   // runs every frame while not paused

A settled state machine stops advancing but is still redrawn every vsync. In our app, four small control views (autoPlay, data-bound, no looping timelines) kept the UI thread busy at about 30–44 ms per frame while nothing on screen changed (Surface Duo, dumpsys gfxinfo: about 260 frames in 5 s).

Two contributing factors:

  1. The loop's skip condition ignores settled. if ((paused || settled) && !needsRedraw) would fix it.
  2. settled is only set from the deprecated CommandQueue.settledFlow, which is fed by StateMachineSettlingStore. That store only accepts a settlement matching a pending request ID, set by unsettle, and the view never calls unsettle. In our testing settled never became true, so fixing (1) alone made no measurable difference. This is from reading the 11.12.1 bytecode plus device measurements; we didn't add native logging.

Workaround in our app: pause() the view about 600 ms after the last view-model write (longest timeline × 2), and resume with playIfNeeded(). Idle frames went from about 260 to 0 per 5 s, and controls still animate on input.

Happy to open a PR for (1) and wire the view to the non-deprecated settle API if you can point at the intended public surface.

Dominant language
TypeScript
Stars
155
Forks
17
Avg merge
1d 10h
Merged PRs (30d)
20

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from rive-app/rive-nitro-react-native

All issues in rive-app/rive-nitro-react-native

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.