Updated 2026-10-13: This article was written in 2014. Its source excerpts have been checked against AOSP
android-4.4.4_r2. Overdraw remains relevant, but ADT, monitor, Hierarchy Viewer, and the old OpenGL tracing workflow are outdated. Android Studio 3.1 and later use Layout Inspector for hierarchy inspection; use Perfetto for frame timing. The historical source is retained below, with Android 12 and Android 16 boundaries added.
It’s been a while since my last update. After joining a new company, things have been busy, but I’ve been spending a lot of time researching Android performance. I’ve realized there’s so much I still don’t know, so I’m starting from the application level and working my way down. This series will document my learnings on Android performance optimization.
First, we’ll discuss GPU Overdraw, which is often the most direct point of contact for developers. This topic is split into two parts: Part 1 covers the theory and optimization suggestions, and Part 2 will walk through a practical optimization example.
What is Overdraw?
GPU overdraw means drawing the same pixel more than once within a frame. For example, drawing a TextView background and then its text can draw the pixels under the characters twice. Extra shading, blending, and memory accesses cost resources, but whether they cause missed frames depends on area, transparency, GPU capabilities, and the rest of the frame’s work. A color overlay alone cannot establish the performance impact. See Android’s overdraw guide.
Start with Debug GPU Overdraw to locate repeatedly drawn regions, then inspect their backgrounds and hierarchy in Layout Inspector. Compose recomposition counts and pixel overdraw measure different things and cannot substitute for each other.
After making a change, turn off debug coloring and compare frame timing on the same device, refresh rate, and interaction. On Android 12 (API 31) and later, Perfetto FrameTimeline can relate application and SurfaceFlinger frames; the data source currently does not support SurfaceView. Removing an app background does not by itself prove that SurfaceFlinger composition became faster.
Causes of Overdraw
- Multiple backgrounds or custom drawing operations cover the same area, with some pixels completely hidden by opaque content.
- Translucent content needs to blend with underlying pixels, so those pixels cannot simply be skipped.
- A drawing sequence repeatedly submits graphics that add nothing visible.
View count, nesting depth, and inflation time are separate concerns. A parent that draws no background or content can add layout work without adding pixel overdraw. A flat custom View can still draw the same pixel many times.
Impact of Poor XML Layouts
- Inflation reads compiled layout resources, constructs Views, and applies attributes. This is primarily CPU work; node count, constructors, and attribute handling affect its cost, not the number of GPU drawing layers directly.
- Layout changes can trigger measurement and placement, while visual updates require recording and executing draw commands. Every frame does not necessarily repeat inflation or a complete layout pass. Use a trace to determine whether the cost is creation, measurement, layout, drawing, or waiting.
Basic Tools for Detecting Overdraw
On supported devices, enable Developer Options → Debug GPU Overdraw → Show overdraw areas. The original Meizu dialer code and menu path were specific to the historical device, not general instructions for current devices. The overlay primarily describes the app window drawn by HWUI; it is not a complete GPU counter for every Surface on the device.
Distinguish total draws from extra draws. The default colors in the Android 4.4.4 implementation checked for this article correspond to:
| Color | Total draws of the pixel | Draws beyond the first |
|---|---|---|
| Original color, no debug tint | 1 | 0 |
| Blue | 2 | 1 |
| Green | 3 | 2 |
| Light red | 4 | 3 |
| Red | 5 or more | 4 or more |
Blue still means overdraw. My checks at the time were at most 2x, no 4x, and 3x covering less than a quarter of the screen. These were project guidelines, not universal Android acceptance criteria. The colors help locate areas to investigate; whether a change is worthwhile also depends on frame cost and visual requirements. Text, rounded corners, shadows, and translucent effects can legitimately require overlapping draws.
Optimization Tools
1. Lint
Android Studio lint checks layout and code issues, and projects can run their Gradle lint tasks. Editor hints do not prove that the full lint task has run. Rules and severity depend on the project’s Android Gradle Plugin / lint version and configuration. See the lint guide.
The following historical screenshot is retained; it is not the current Android Studio interface:

2. Common Lint Suggestions and Their Limits
- Compound drawables: A TextView compound drawable can replace separate image/text nodes when they do not need independent layout, interaction, or accessibility semantics.
- Merge root frame: Consider
<merge>only when the root has no required background, padding, layout, or interaction behavior and an appropriate host parent exists. It is not a standalone View. - Useless leaf / parent: Check custom drawing, foregrounds, interaction, animation, and accessibility before removing a node. An absent background alone does not establish that it is useless.
- Deep layouts: Nesting can increase measurement and layout work. The official layout guide lists a default depth-warning threshold of 10, subject to tool version and configuration. That is a static-analysis clue, not a rule that every hierarchy deeper than 10 drops frames.
These suggestions primarily concern View/XML layouts. Preserve layout behavior and semantics when resolving warnings. See layout hierarchy optimization.
3. Hierarchy Viewer and Layout Inspector
Hierarchy Viewer is no longer maintained. It displayed view trees and relative measure/layout/draw costs through Android Device Monitor. Connectivity depended on system builds, debugging capabilities, and protocol support, not disk encryption. Adding ViewServer for that old workflow is historical advice.
Use Layout Inspector in Android Studio 3.1 or later to inspect runtime hierarchy and attributes. It does not replace frame profiling: use system traces, frame metrics, or application measurements to establish timing costs.
Layout Optimization Principles
- LinearLayout suits simple rows and columns; compare ConstraintLayout or other options for complex View layouts. Container names alone do not rank performance, and View/XML measurement rules do not directly apply to Compose.
- Reuse layouts through
<include>. Where host requirements are satisfied, use<merge>to remove a behaviorless intermediate container. - Use ViewStub to postpone creation of content not needed initially. Changing visibility on an existing View does not create the objects again, so dynamic inflation is not inherently faster than
setVisibility(). ViewStub moves work to first expansion rather than eliminating it. - Remove backgrounds only when they make no visible contribution. The covering content must remain fully opaque over the affected area. Check empty lists, scrolling edges, loading, errors, pressed states, and transitions.
- A selector’s normal state can omit drawing when the design allows it. Do not blindly replace every normal background with transparency or remove selection, press, and accessibility feedback.
- Nested weighted LinearLayouts can require additional measurement passes. This is a measure-stage cost, not a guarantee that every child draws twice. Consider MeasureSpec conditions and actual traces.
- Remove unnecessary nodes and repeated measurements while preserving semantics. Optimize measured cost rather than the appearance of the hierarchy diagram.
Source Code References
If you’d like to follow this into the source, take a look at OpenGLRenderer.cpp in AOSP android-4.4.4_r2. These excerpts depend on HWUI internal state: renderOverdraw() maps stencil counts to debug colors, and countOverdraw() reads the debug result and calculates an average.
1 | void OpenGLRenderer::renderOverdraw() { |
glReadPixels() belongs to that historical diagnostic implementation. Adding a readback to every application frame is not an optimization, and the returned average is not GPU time in milliseconds.
The numerical overlay comes from frameworks/base/core/java/android/view/HardwareRenderer.java at the same tag. These are excerpts of debugOverdraw() and drawOverdrawCounter(). The corresponding file at AOSP android-5.0.0_r1 no longer contains these methods, so this is not a current-system entry point:
1 | private void debugOverdraw(View.AttachInfo attachInfo, Rect dirty, |
These excerpts describe Android 4.4.4, not modern HWUI source organization. For example, AOSP Android 16 tag android-16.0.0_r1 calls renderOverdraw() from a Properties::debugOverdraw branch in SkiaPipeline.cpp. Pin the source tag for the target device before tracing its rendering backend.
Reference Articles
- Original optimization case study (historical reference; not accessible during this review)
- Decompiling and Adding GPU Display
- Optimizing Layouts
- Reusing Layouts
- Loading Layouts On-Demand
- RecyclerView guide (the old Smooth Scrolling URL now redirects here)
- Hierarchy Viewer Documentation
- Lint Tips
About Me && Blog
Here’s my personal introduction and related links. I look forward to exchanging ideas with fellow developers - “When three walk together, there must be one who can be my teacher!”
- About the Author : Includes my WeChat and WeChat group links.
- Blog Content Navigation : A navigation guide to my blog content.
- Personally Curated Excellent Blog Articles - Must-Know Android Performance Optimization : Welcome to recommend articles (contact me via WeChat).
- Android Performance Optimization Knowledge Planet: The paid community stopped operating in 2026 and no longer accepts new members; this link preserves its history.
One person can walk faster, but a group can walk farther.
