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 comes performance challenges. Layouts draw faster and use less power and battery if you spend time designing them in the most efficient way. For example:
You should be able to:
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.
Create an app called StackedViews that stacks views on top of each other.
TextViewelement where the width and height match the parent. Set a light gray background, such as
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 #
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
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>
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:
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.
Important: If it's hard for you to see the difference between the colors that the tool shows, try adjusting the tool for deuteranomaly:
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:
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.
Viewdisplays an image that fills it, the background is completely covered, so it can be removed.
To reduce overdraw for the StackedViews app, rearrange the views in the app so that they do not overlap. In the XML code:
ConstraintLayout, because it's invisible.
layout_heightof each view to
layout_marginTopfor view2 and view3, or set it to
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.
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
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
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.
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:
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 the preview, you can only see outlines around View 1 and View 3, which are on top.
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:
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:
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.
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:
How much time does your app have available to calculate and display one frame of content?
What are some techniques you can use to make rendering faster?
Which answer best describes the measure-and-layout stage of the rendering pipeline?
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.
To see all the codelabs in the Advanced Android Development training course, visit the Advanced Android Development codelabs landing page.