Simplify Complex View Hierarchies
At the heart of your app is the hierarchy of views that makes up the user interface and the visual experience of users. With feature-rich apps, this hierarchy grows large and complex and can become a source of performance problems. The most likely symptom you will see is a generic general slowness of the app, especially when rendering complex views to the screen.
Simplifying or rearranging the view hierarchy of your app can improve performance, especially on lower-end devices and earlier versions of Android. As an added benefit, your app will become easier to maintain overall.
Pre-work: If you have not done so already, reduce overdraw by removing unnecessary backgrounds to eliminate a common source of slowness that is not related to your view hierarchy.
Analyze the view hierarchy
Analyzing the view hierarchy is an example of using several tools together to pinpoint and fix performance problems. So, you may need to use just one, or all of these tools to optimize performance.
Profile GPU Rendering
- Run the Profile GPU Rendering tool and look at the BLUE segments of the bars. If the blue segments are tall and causing the bars to cross the 16 mspf line, your app spends a lot of time updating display lists. The M release of Android adds additional color segments, and the light-green Measure/Layout segment may also be larger than expected. One reason for this can be view hierarchies that are unnecessarily complex. This only tells you there may be a problem, it doesn’t tell you, where to look. So, let’s move forward.
Show GPU View Updates
- Run the Show GPU View Updates tool on your mobile device. In Developer Options, scroll to Hardware accelerated rendering and turn on Show GPU view updates.
- Interact with your app.
- Views on the screen that are updated will flash red. If you notice that parts of your screen are flashing, and they have nothing to do with the area that’s being updated, there may be a connection in the view hierarchy that’s causing them to be invalidated improperly. As such, you can focus your efforts on these areas to find problems faster.
This is the tool, where you’ll do the heavy lifting.
- Start the Hierarchy Viewer tool.
- Find the areas of the view hierarchy where you still see a lot of overdraw in your app. Consider whether restructuring your views could reduce overdraw.
- Identify areas where your view hierarchy is complex, and consider how you could simplify it.
- Profile the view hierarchy from Hierarchy Viewer to confirm or identify additional potential problem spots.
Deep-dive with lint
Use the lint tool on your layout files to search for possible view hierarchy optimizations…however, the awesomeness of lint is for another article.
Simplify your view hierarchy
Remove views that do not contribute to the final image
To identify views that do not contribute to the final image on the screen:
- In Hierarchy Viewer, walk through the hierarchy starting from the leaves towards the root.
- Click each node to see how the screen looks at that node. Alternatively, look at the Layout View window to see how views are layering themselves.
- If a view that was previously visible becomes fully hidden, then you may not need that view at all, as shown in Figure 1.
- Eliminate from your code the views that are completely covered, never displayed, or outside the screen.
Flatten the view hierarchy to reduce nesting
- Does your view hierarchy have parts that look like the nested arrangement on the left of Figure 2?
- Flatten the view hierarchy by replacing nested linear layouts with relative layouts wherever possible.
See Optimizing Layout Hierarchies.
Reduce the number of views
- If your user interface has many simple views, you may be able to combine some of them without diminishing the user experience, as shown in Figure 3.
- Both the changes below may affect how you present information to the user and will include design trade-offs. Remember that performance is more important than anything else for your app’s success, and opt for simplicity wherever you can.
- Reduce the number of views by combining them into fewer views. For example, you can combine text views if you reduce the number of fonts and styles.
- Redesign your app’s user interface to use fewer views.
Simplify nested layouts that trigger multiple layout passes
Some layout containers, such a RelativeLayout, require two layout passes in order to finalize the positions of their child views. As a result, their children also require two layout passes. When you nest these types of layout containers, the number of layout passes increases exponentially with each level of the hierarchy.
For example, a view inside a grid view inside a list view inside a relative layout could get laid out 8 times(!) as shown in Figure 4.
- Linear layouts that also use measureWithLargestChild.
- Grid views that also use gravity.
- Custom containers that are subclasses of the above.
- Some uses of weights can also trigger multiple layout passes.
Using any of these containers as the root of a complex view hierarchy, the parent of a deep subtree, or using many of them in your layout, can hurt performance. So, consider whether you can achieve the same layout using a container configuration that does not result in these exponential numbers of layout passes. For example, you could replace a relative layout with a grid view (without gravity) as your root view.
Watch this screencast to see all these techniques in action.
For the cabaret version, see Double Layout Taxation. For more tips, see Optimizing Layout Hierarchies. For more videos, check out Android Performance Patterns on YouTube. If you want to jump ahead, investigate the Android Performance Course on Udacity. But most importantly, join our Android Performance G+ Community for great tips about, you guessed it, building performant Android apps, because…#perfmatters.