Skip to content

Performance: isolate Home preview recomposition, cache category queries, add baseline profiles - #162

Open
amazd wants to merge 4 commits into
Davidona:masterfrom
amazd:perf-home-and-startup
Open

Performance: isolate Home preview recomposition, cache category queries, add baseline profiles#162
amazd wants to merge 4 commits into
Davidona:masterfrom
amazd:perf-home-and-startup

Conversation

@amazd

@amazd amazd commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Three performance improvements targeting Home screen smoothness and cold start, especially on lower-end devices (Fire TV):

  • Isolate live-preview recomposition. Preview playback state (channel id, engine, loading/error) moves out of HomeUiState into a dedicated HomePreviewUiState flow, read only inside a new HomeLivePreviewHost composable. Playback ticks while a stream spins up or rebuffers now recompose just the preview pane instead of the entire Home screen.
  • Compose stability config. compose-stability.conf marks cross-module immutable classes (com.streamvault.domain.model.**, java.time.**) as stable so composables taking them as parameters can skip recomposition; they were previously inferred unstable because :domain doesn't run the Compose compiler.
  • Stale-while-revalidate category cache. getCategories() runs a GROUP BY aggregate over the whole channels table (50k+ rows on large providers). It is now shared per provider via shareIn(replay = 1), so re-entering a screen renders instantly from replay while Room refreshes in the background. WhileSubscribed(0) stops the upstream query when unobserved so catalog syncs don't keep re-running it.
  • Baseline profiles. New :baselineprofile Macrobenchmark module generates startup + Home hot-path profiles (checked in for release/beta); profileinstaller applies them at install time so sideloaded builds get AOT-compiled hot paths instead of cold JIT. Refresh with ./gradlew :app:generateBaselineProfile.

Test plan

  • Home screen: open PRO mode, focus channels to start previews — verify preview pane updates (loading spinner, error message) without visible jank in the channel grid
  • Preview handoff to fullscreen and back still works; keep-screen-on flag still tracks active preview
  • Categories: navigate away/back on a large provider — list appears instantly, updates after sync
  • Release build installs and startup feels faster on Fire TV (profileinstaller applies profile)

🤖 Generated with Claude Code

amazd added 4 commits July 7, 2026 11:43
Preview playback ticks (loading/error transitions while a stream spins up
or stalls) used to republish the entire HomeUiState, recomposing the whole
Home screen. Preview state now lives in its own HomePreviewUiState flow,
read only inside the new HomeLivePreviewHost composable so playback ticks
recompose just the preview pane.
Domain models and java.time types come from modules that don't run the
Compose compiler, so they were inferred unstable and forced recomposition
of every composable taking them as parameters. compose-stability.conf
marks them stable so those composables can skip when inputs are unchanged.
getCategories() runs a GROUP BY aggregate over the whole channels table
(50k+ rows on large providers) and re-ran cold on every screen entry.
The flow is now shared per provider via shareIn(replay = 1): re-entering
a screen renders the last list instantly while Room refreshes it in the
background. WhileSubscribed(0) stops the upstream query as soon as the
last subscriber leaves so catalog syncs don't keep re-running the heavy
aggregate with nobody watching.
New :baselineprofile module (Macrobenchmark + UiAutomator) generates
profiles covering app startup and the Home screen hot paths; generated
profiles for the release and beta variants are checked in. The
profileinstaller dependency installs them at install time so sideloaded
builds (Fire TV has no Play Store cloud profiles) get AOT-compiled hot
paths instead of cold JIT. Refresh with:
./gradlew :app:generateBaselineProfile
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant