While engineering a Nike-inspired 3D e-commerce showcase in Jetpack Compose, I ran into a classic UI jank issue on screen transitions. My first theory was Android's predictive back gesture. My second theory was Compose recomposition loops fighting the UI thread. I was wrong on both counts.
What the data actually said
Profiling real frame-timing data on a physical Pixel 8 Pro using Android's frame-stats tooling told a different story:
- GPU render times were consistently fast — under 3ms. The UI thread was the bottleneck, not the GPU.
- Android Studio's Layout Inspector was still attached to the running process, actively stealing CPU cycles inside the app's own trace.
- The real fix was smaller than either theory: adding a stable
key()on cross-fading list content, and eliminating a double-computation loop that was running per frame.
The lesson
If you don't profile on real hardware, you aren't optimizing — you're making educated guesses, and educated guesses on Compose specifically tend to point at recomposition or gesture handling first because those are the fashionable suspects. The actual bottleneck is often a tooling artifact or a stale key, and you only find that by measuring instead of theorizing.