Performance
This guide covers performance optimization strategies for the Privacy Boost Android SDK. The native binary is small enough that bundle size is rarely the bottleneck — the costs to manage are SDK init, proof generation, balance refresh frequency, and coroutine hygiene.SDK Lifecycle
One Instance Per Process
PrivacyBoost holds a JWT, identity keys, and an internal note cache. Initialize it once and inject it via your DI container of choice (Hilt, Koin, manual Application-scoped singleton).
Defer Init Until First Use
If your app has flows that don’t touch the privacy pool (onboarding, marketing screens), defer SDK construction until the first gated route. The Rust core does some setup work on first call — keep it off the cold-start path.Coroutine Scope Hygiene
All network/proof methods aresuspend — call them from a structured scope, not a fire-and-forget GlobalScope.launch.
Use Lifecycle-Aware Scopes
viewModelScope cancels when the ViewModel is cleared, so a deposit that’s still proving when the user navigates away gets cleanly cancelled instead of leaking.
Run on the Right Dispatcher
The SDK does its own native work and is safe to call fromDispatchers.Main, but if you’re chaining heavy serialization or DB writes around it, hop to Dispatchers.Default or Dispatchers.IO:
Balance Refresh
Don’t Poll From Every Composable
getBalance(token) and getAllBalances() hit the network. Centralize refreshes through a single repository / StateFlow and let UI subscribe.
Mutex collapses concurrent calls — overlapping refreshes wait on the in-flight one.
Refresh on Resume, Not on a Timer
Tying refresh to adelay() loop drains battery. Tie it to lifecycle events:
WorkManager with a minimum-interval periodic request — not a foreground service.
Network
Parallelize Independent Reads
Sequential awaits serialize unnecessarily. Useasync:
Page History — Don’t Fetch It All
Pass a smalllimit and use the returned cursor for pagination:
Memory
Trim When Backgrounded
If your app stays in the background long enough to receiveonTrimMemory(TRIM_MEMORY_BACKGROUND) or higher, drop non-essential caches — pending transaction lists, off-screen history pages — but keep the SDK instance.
Use Stable Keys in Lists
In LazyColumn, key transactions bytxHash so Compose reuses items instead of rebuilding:
Operation Timing
Wrap SDK calls to observe timing in development:What the SDK Already Optimizes
Things you do not need to layer on top:- Note cache — the SDK caches unspent notes locally and only refetches new merkle tree leaves.
- Merkle tree pruning — proven nodes are kept; the rest are pruned.
- JWT reuse —
clearSession()keeps identity keys so the nextauthenticate()is fast.
Best Practices Summary
- One SDK instance per process — hold it in
Applicationor your DI graph. - Defer SDK init until the first privacy-pool screen.
- Use
viewModelScope/lifecycleScope— neverGlobalScope. - Refresh balances on
ON_RESUMEand after writes, not on a timer. - Deduplicate concurrent refreshes with a
Mutexor single shared flow. - Parallelize independent reads with
async. - Page transaction history; don’t fetch it all.
- Use
clearSession()overlogout()when re-auth is expected soon.