This codelab is part of the Advanced Android Development training course, developed by the Google Developers Training team. You will get the most value out of this course if you work through the codelabs in sequence.
For complete details about the course, see the Advanced Android Development overview.
You can make your apps interesting and visually compelling by following Material Design guidelines, creating nested hierarchies of layouts, and using drawables as background elements for your views. However, with increasing complexity come performance challenges. Layouts draw faster and use less power and battery if you spend time designing them in the most efficient way. For example:
- Overlapping views result in overdraw, where the app wastes time drawing the same pixel multiple times, and only the final rendition is visible to the user. Size and organize your views so that every pixel is only drawn once or twice.
- Deeply nested layouts force the Android system to perform more passes to lay out all the views than if your view hierarchy is flat.
- To simplify your view hierarchy, combine, flatten, or eliminate views.
What you should already know
You should be able to:
- Create apps with Android Studio and run them on a mobile device.
- Work with the Developer options settings on a mobile device.
What you'll learn
- Run the Debug GPU Overdraw tool to visualize Android drawing to the screen.
- Use the Layout Inspector tool to inspect the view hierarchy of an app.
What you'll do
- Create a testing app, StackedViews, to illustrate overdraw.
- Run the Debug GPU Overdraw tool on the StackedViews app.
- Fix the StackedViews app to reduce overdraw.
- Use the Layout Inspector tool to identify how you could simplify the view hierarchy.
The StackedViews app arranges three overlapping
TextView objects inside a
ConstraintLayout to demonstrate overdraw. While this is a contrived and simplistic example, overlapping views can easily happen during development as you add more features and complexity to your app. The screenshot below shows an arrangement of three overlapping views. View 1 fills the screen. View 2 fills the bottom two thirds of the screen. View 3 fills the bottom third of the screen to create progressively more overlap.
One possible cause for slow rendering performance is overdraw, which is when your app draws over the same area multiple times, but the user sees only what has been drawn last. This can result in performance problems, especially for older or less powerful devices.
Learn more about overdraw in the Rendering and layout concept chapter.
1.1 Create an app to illustrate overdraw
Create an app called StackedViews that stacks views on top of each other.
- Create an app using the Empty template, which uses
- Set a light gray background on the
- Add a
TextViewelement where the width and height match the parent. Set a light gray background, such as
- Add a second, overlapping,
TextViewelement. Make the width match the parent. Make the height about three quarters of the height from the bottom. You can do this by making the height match the parent, then use
layout_marginTopto add space at the top. Use a darker gray background, such as #
- In the same way, add a third, overlapping
TextViewelement that fills the width of the parent and about half of the height from the bottom. Use an even darker gray background, such as
- Optionally, use a large font such as
- Run the app on your device. It should look similar to the screenshot below, with three progressively more overlapping views.
Your final code should look similar to this:
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.android.stackedviews.MainActivity" android:background="@android:color/background_light"> <TextView android:id="@+id/view1" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/very_light_gray" android:text="@string/view1" android:textAppearance="@style/TextAppearance.AppCompat.Display1" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/view2" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="156dp" android:background="@color/light_gray" android:text="@string/view2" android:textAppearance="@style/TextAppearance.AppCompat.Display1" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/view3" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="300dp" android:background="@color/medium_gray" android:text="@string/view3" android:textAppearance="@style/TextAppearance.AppCompat.Display1" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </android.support.constraint.ConstraintLayout>
1.2 Turn on Debug GPU Overdraw on your device
Make sure developer options is turned on. Turn on USB Debugging, and allow it when prompted.
Turn on Debug GPU Overdraw on your mobile device:
- Go to Settings > Developer options.
- In the Hardware accelerated rendering section, select Debug GPU Overdraw.
- In the Debug GPU overdraw dialog, select Show overdraw areas.
- Watch your device turn into a rainbow of colors. The colors hint at the amount of overdraw on your screen for each pixel.
The following key shows which colors indicate how much overdraw.
True color has no overdraw.
Purple/blue is overdrawn once.
Green is overdrawn twice.
Pink is overdrawn three times.
Red is overdrawn four or more times.
An app with too much overdraw will have a lot of pink and red coloring, as shown in the screenshot below.
A properly laid out app has little overdraw and primarily show true and purple coloring, as shown in the screenshot below. Some overdraw is unavoidable, for example, when drawing text onto a background.
- Run the StackedViews app. The screen should look similar to the one below, with green, pink, and red colors that indicate significant areas of overdraw where the
Important: If it's hard for you to see the difference between the colors that the tool shows, try adjusting the tool for deuteranomaly:
- Go to Settings > Developer options.
- In the Hardware accelerated rendering section, select Debug GPU Overdraw.
- In the Debug GPU overdraw dialog, select Show areas for Deuteranomaly to show overdraw using adjusted colors.
Compare the colors of the views in this app with the color key shown above, and you see that View 3 and View 2 are colored for 3x and 4x overdraw. This is because as laid out in the XML file, you stacked the views on top of each other. A
ConstraintLayout with a background is the bottom layer, and View 1 is drawn on top of that, so View 1 is overdrawn twice, and so on.
In a real-world app, you would not use a layout like this, but remember that this is a simple example to demonstrate the tool. Common, realistic examples that produce overdraw include:
- Lists with items that contain thumbnails, text, and controls.
- Custom views, such as custom menus or drawers.
- Views that overlap with other views for any reason.
1.3 Fix overdraw
Fixing overdraw can be as basic as removing invisible views, and as complex as re-architecting your view hierarchy. To fix overdraw, you usually need to take one or more of the following actions.
- Eliminate unnecessary backgrounds, for example, when a
Viewdisplays an image that fills it, the background is completely covered, so it can be removed.
- Remove invisible views. That is, remove views that are completely covered by other views.
- In custom views, clip generously. (See the Rendering and layout concept chapter. You learn about custom views in another chapter.)
- Reduce the use of transparency. For example, instead of using transparency to create a color, find a color. Instead of using transparency to create a shine-through effect for two overlapping images, preprocess the two images into one.
- Flatten and reorganize the view hierarchy to reduce the number of views. See the Rendering and layout concept chapter for examples and best practices.
- Resize or rearrange views so they do not overlap.
To reduce overdraw for the StackedViews app, rearrange the views in the app so that they do not overlap. In the XML code:
- Remove the background of the
ConstraintLayout, because it's invisible.
- Set the
layout_heightof each view to
layout_marginTopfor view2 and view3, or set it to
- Use constraints to lay out the views relative to each other.
The following code shows the constraints for each view:
<TextView android:id="@+id/view1" ... app:layout_constraintBottom_toTopOf="@+id/view2" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/view2" ... app:layout_constraintBottom_toTopOf="@+id/view3" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/view1" /> <TextView android:id="@+id/view3" ... app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/view2" />
Your final layout should produce output from Debug GPU Overdraw similar to one of the images below. (The second image shows overdraw for deuteranomaly.) You draw once for the background, and on top of that, the text.
In a realistic setting without custom views, overdraw may not be a huge performance problem for your app since the Android framework optimizes drawing the screen. However, since overdraw is usually straightforward to find and fix, you should always minimize it so it does not pollute your other performance data.
The process of rendering views to the screen includes a measure-and-layout stage, during which the system appropriately positions the relevant items in your view hierarchy. The "measure" part of this stage determines the sizes and boundaries of
View objects. The "layout" part determines where on the screen to position the
The following recommendations cover the most common cases:
Remove views that do not contribute to the final image.
Eliminate from your code the views that are completely covered, never displayed, or outside the screen. This seems obvious, but during development, views that later become unnecessary can accumulate.
Flatten the view hierarchy to reduce nesting
Android Layouts allow you to nest UI objects in the view hierarchy. This nesting can impose a cost. When your app processes an object for layout, the app performs the same process on all children of the layout as well.
Keep your view hierarchy flat and efficient by using
ConstraintLayout wherever possible.
Reduce the number of views
If your UI has many simple views, you may be able to combine some of them without diminishing the user experience.
- Combining views may affect how you present information to the user and will include design trade-offs. Opt for simplicity wherever you can.
- Reduce the number of views by combining them into fewer views. For example, you may be able to combine
TextViewobjects if you reduce the number of fonts and styles.
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. See the Optimizing View Hierarchies documentation and the Double Layout Taxation video.
Be conscious of layout passes when using:
LinearLayoutthat also use
GridViewthat also use
- Custom view groups that are subclasses of the above
- Weights in
LinearLayout, which can sometimes trigger multiple layout passes
Using any of the above view groups 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. Consider whether you can achieve the same layout using a view group configuration that does not result in these exponential numbers of layout passes, such as a
2.1 Inspect your app's layout with Layout Inspector
The Layout Inspector is a tool in Android Studio that allows you see your view hierarchy at runtime.
Design view shows you the static layout of an activity as defined in your XML files, but it does not include any views that you might create, destroy, or move at runtime.
Inspecting the view hierarchy can show you where you might simplify your view hierarchy. In addition, the Layout Inspector can also help you identify overlapping views. If Debug GPU Overdraw shows that your app has overdraw, you may need to run Layout Inspector to identify the exact views involved, or to help you determine which views you might be able to rearrange.
With Layout Inspector you take a snapshot of the view hierarchy of a running app and display it for inspection.
- Run the original StackedViews app that has the overlapping views.
- Choose Tools > Android > Layout Inspector in Android Studio.
- Choose your app process to attach to
Layout Inspector takes a snapshot of your view hierarchy and displays it in a separate tab in Android Studio.
In the standard tool layout you see three panes:
- The left pane, the View Tree, shows the view hierarchy as a tree of class names. Click on any view. More information appears about the view in the Properties Table, and the view's outline is highlighted (with a thin outline) in the center panel.
- The center panel shows a preview of the app. Think of it as an annotated screenshot. Click on any part of of the screen to see more information about the associated top-level view in the Properties Table.
- The right-hand panel, the Properties Table, shows all the properties for the selected view.
2.2 Find overlapping views
If your layout includes completely overlapping views, then by default, only the front-most view is clickable in the screenshot. To make the view behind clickable, right-click the front-most view in the View Tree panel and uncheck Show in preview, as follows:
- In your code, change the size of View 2 to completely cover View 3. In the layout for
- Run the app.
- Open the Layout Inspector. Tools > Android > Layout Inspector.
In the preview, you can only see outlines around View 1 and View 3, which are on top.
- In the Tree View, right-click View 3 and deselect Show in preview.
- In the Tree View, right-click View 1 and deselect Show in preview.
ConstraintLayoutin the Tree View. Now if you mouse over the preview, the only outline you see is around the hidden View 2, and View 2 is highlighted in Tree View.
Layout Inspector does not connect to your running app. It creates a static capture based on your code.
You can find the captures Android Studio made in the captures folder of your Android Studio project. The files use the package name and the date, and have a
.li extension (for example,
com.example.android.largimages_2017.4.12_12.01.li). In Project view, expand the captures folder and double-click any capture file to show its contents.
Inspecting the view hierarchy, the view arrangement and boundaries, and the properties of each view can help you determine how to optimize your app's view hierarchy.
Android Studio projects:
- Use the Debug GPU Overdraw tool to identify overlapping views.
- Reduce overdraw by removing unused backgrounds and invisible views; use clipping to reduce overlapping of views.
- Use the Layout Inspector to investigate your view hierarchy.
- Simplify your view hierarchy by flattening the hierarchy, combining views, eliminating invisible views, or rearranging your layout.
The related concept documentation is in 4.1 Rendering and layout.
Android developer documentation:
This section lists possible homework assignments for students who are working through this codelab as part of a course led by an instructor. It's up to the instructor to do the following:
- Assign homework if required.
- Communicate to students how to submit homework assignments.
- Grade the homework assignments.
Instructors can use these suggestions as little or as much as they want, and should feel free to assign any other homework they feel is appropriate.
If you're working through this codelab on your own, feel free to use these homework assignments to test your knowledge.
Build and run an app
Use the app that you created for the homework assignment in the 4.1 Part A: Profile GPU Rendering tool codelab.
In the app, make the following changes:
- Use the same (larger) images for the thumbnails as for the details view. Run Profile GPU Rendering with the app and take a screenshot of the bars.
- Change the app to use text or small thumbnail images to list the items. Run Profile GPU Rendering with the app again and take a screenshot of the bars.
- Do the two screenshots look different? Comment on the difference or lack of difference.
- Turn on Debug GPU Overdraw. Take a screenshot of your app. If there is a lot of red color, use Layout Inspector to fix your app, then take another screenshot.
Answer these questions
How much time does your app have available to calculate and display one frame of content?
- 16 milliseconds
- Less than 16 milliseconds, because the Android framework is doing work at the same time as your app does work.
- It depends on the device.
What are some techniques you can use to make rendering faster?
- Reduce overdraw.
- Move work away from the UI thread.
- Use smaller images.
- Compress your data.
- Flatten your view hierarchy.
- Use as few views as possible.
- Use loaders to load data in the background.
- Use efficient views such as
Which answer best describes the measure-and-layout stage of the rendering pipeline?
- The GPU measures device dimensions and appropriately sizes views.
- The system traverses the view hierarchy and calculates the size and position of each view inside the view's parent, relative to other views.
- The system optimizes layout times for your views.
Submit your findings for grading
No app to submit for this homework assignment.
Submit the two screenshots you took with Profile GPU Rendering turned on, and the final screenshot you took with Debug GPU Overdraw turned on. Also submit your reflections on why the two screenshots that show Profile GPU Rendering output might be (almost) the same, or why they are different.
Guidance for graders
- Student submitted two screenshots of the app with Profile GPU Rendering turned on
- Screenshots are different.
- Student submitted comments explaining the difference.
- If there is no difference, student should reflect on why not.
- If there is a difference, students should reflect on what may have caused it.
- Student submitted one screenshot of the app with Debug GPU Overdraw turned on, and this screenshot shows only a little bit of red coloring.
To see all the codelabs in the Advanced Android Development training course, visit the Advanced Android Development codelabs landing page.