In the Overview of Jank and Frame Drops in Android - System Layer article, we listed causes of jank originating from the system. In this article, we focus on causes stemming from the App itself. When you encounter lag, before blaming the phone manufacturer, consider if it’s the App’s own inefficiency.
Jank issues are a top priority for both phone manufacturers and app developers, often handled by dedicated “Performance” or “Stability” teams. Third-party tools like Tencent’s Matrix are excellent, but manufacturers often have proprietary solutions with deeper system access through source code modification.
Smoothness refers to frame drops. If the screen fails to refresh at 60 FPS (or the target refresh rate) and only hits 55, the user perceives this as jank. Frame rate fluctuations are especially noticeable.
This series includes:
0. Overview of Jank and Frame Drops in Android - Methodology
- Overview of Jank and Frame Drops in Android - System Layer
- Overview of Jank and Frame Drops in Android - Application Layer
- Overview of Jank and Frame Drops in Android - Low Memory
Application-Side Performance Issues
As noted in the system-layer article, many of these cases can be identified using Systrace. If you’re unfamiliar, see the Systrace Series. Systrace provides a global view of the system’s operating state.
1. App Main Thread Execution Overhead
Operations like Input processing, Animation execution, Measure, Layout, Draw, and decodeBitmap on the main thread can cause jank if they exceed the frame budget.
Measure / Layout Overhead
If the view hierarchy is too complex, onMeasure and onLayout can take a significant amount of time, delaying the frame.
Draw Overhead
Complex custom drawing or heavy canvas operations contribute to main thread latency.
Animation Callback Overhead
Long-running logic within Animation callbacks or Choreographer frames will delay the start of the rendering pipeline.
View Initialization Overhead (PlayStore Example)
Inflating complex XML layouts on the main thread is a common source of jank during navigation.
List Item Initialization Overhead (WeChat Example)
Inefficient getView or onBindViewHolder implementations in lists lead to stutter during scrolling.
decodeBitmap Overhead
Decoding large images on the main thread is a classic performance anti-pattern.
2. uploadBitmap Overhead
This refers to uploading a bitmap to the GPU (texture upload). Large bitmaps or textures that change every frame increase RenderThread workload significantly.
3. BuildDrawingCache Overhead
Frequent calls to buildDrawingCache can cause the main thread to exceed the Vsync period. WeChat’s dynamic stickers sometimes suffer from this.
4. Software Rendering vs. Hardware Rendering
If an Activity explicitly disables hardware acceleration, drawing falls back to Skia on the CPU. This significantly increases UI Thread load and almost always results in lag. For more, see Detailed Explanation of Hardware Layer in Android.
5. Main Thread Binder Latency
During Activity Resume, communicating with AMS requires the AMS lock. If the background is busy, waiting for this lock can cause delays, especially during multi-tasking gestures.
6. Uneven Game Content Drawing (SurfaceView)
In games, even if SF is ready, the game engine might deliver frames unevenly. If a game frame misses the SF Vsync window, it will be dropped.
7. WebView Inefficiency
Complex web pages in a WebView often exhibit poor performance since the WebView’s rendering can be heavier than native components.
8. Refresh Rate Mismatch
A mismatch between the screen’s refresh rate and the content’s FPS can cause a lack of fluidity, such as 60 FPS animations on a 90 Hz screen.
9. Incompatibility with High Refresh Rates
Apps designed for 60 FPS machines (16.6ms budget) might struggle on 90 Hz or 120 Hz screens (11.1ms or 8.3ms budget). If drawing takes 14ms, it’s fine for 60Hz but will stutter on 90Hz.
10. Main Thread I/O Operations
Classic issues include performing database queries or using SharedPreferences.commit() (which is synchronous) instead of apply() on the main thread.
11. WebView/Main Thread Interaction
Synchronization issues or heavy JS-to-Native bridges between a WebView and the main thread can cause freezing.
12. RenderThread Overhead
If the RenderThread itself is overloaded (too many GPU commands), the total frame time will exceed the Vsync interval. This also blocks the main thread’s next sync operation.
13. Multiple RenderThreads Synchronization
Some apps spawn multiple RenderThreads. Synchronizing these threads can sometimes incur significant overhead, blocking the main thread.
Summary
Android is an evolving platform, but its openness means app quality varies wildly. Unlike the tightly controlled App Store, Android apps come from many sources with varying levels of quality control.
Large companies usually prioritize performance, but feature bloat (like WeChat’s memory footprint or QQ’s increasing complexity) still leads to issues. Smaller devs might lack the resources for deep optimization. Furthermore, “black tech” tactics like aggressive keep-alive, mutual wake-ups, and heavy background tasks degrade the overall user experience.
When we find app-specific performance flaws that persist across different hardware, we often reach out to the developers to collaborate on a fix.
For more details on what OEMs do, see: What do phone manufacturers actually do when they say they are optimizing Android?
This series includes:
0. Overview of Jank and Frame Drops in Android - Methodology
- Overview of Jank and Frame Drops in Android - System Layer
- Overview of Jank and Frame Drops in Android - Application Layer
- Overview of Jank and Frame Drops in Android - Low Memory
About Me && Blog
(Links and introduction)