Docs: New doc on optimizing view hierarchies for upcoming Performance section
Bug: 29514404 This is part of the new Performance section to be launched on DAC soon. Change-Id: Ib590a97f9b7696251edbdecb28305933014483b7
This commit is contained in:
BIN
docs/html/topic/performance/images/lint-display.png
Normal file
BIN
docs/html/topic/performance/images/lint-display.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 58 KiB |
BIN
docs/html/topic/performance/images/lint-inspect-code.png
Normal file
BIN
docs/html/topic/performance/images/lint-inspect-code.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
388
docs/html/topic/performance/optimizing-view-hierarchies.jd
Normal file
388
docs/html/topic/performance/optimizing-view-hierarchies.jd
Normal file
@@ -0,0 +1,388 @@
|
||||
page.title=Performance and the View Hierarchy
|
||||
@jd:body
|
||||
|
||||
<div id="qv-wrapper">
|
||||
<div id="qv">
|
||||
|
||||
<h2>In this document</h2>
|
||||
<ol>
|
||||
<li><a href="#lmp">Layout-and-Measure Performance</a>
|
||||
<ol>
|
||||
<li><a href="#managing">Managing complexity: layouts matter</a></li>
|
||||
<li><a href="#double">Double taxation</a></li>
|
||||
</ol>
|
||||
</li>
|
||||
<li><a href="#dx">Diagnosing View Hierarchy Issues</a>
|
||||
<ol>
|
||||
<li><a href="#systrace">Systrace</a></li>
|
||||
<li><a href="#profile">Profile GPU rendering</a></li>
|
||||
<li><a href="#lint">Lint</a></li>
|
||||
<li><a href="#hv">Hierarchy Viewer</a></li>
|
||||
</ol>
|
||||
</li>
|
||||
<li><a href="#solving">Solving View Hierarchy Issues</a>
|
||||
<ol>
|
||||
<li><a href="#removing">Removing redundant nested layouts</a></li>
|
||||
<li><a href="#cheaper">Adopting a cheaper layout</a></li>
|
||||
</ol>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<p>
|
||||
The way you manage the hierarchy of your {@link android.view.View} objects can
|
||||
have a substantial impact on your app’s performance. This page describes how to
|
||||
assess whether your view hierarchy is slowing your app down, and offers some
|
||||
strategies for addressing issues that may arise.
|
||||
</p>
|
||||
|
||||
<h2 id="lmp">Layout and Measure Performance</h2>
|
||||
<p>
|
||||
The rendering pipeline includes a <em>layout-and-measure</em>
|
||||
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 {@link android.view.View} objects. The layout part determines where on the screen to
|
||||
position the {@link android.view.View} objects.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Both of these pipeline stages incur some small cost per view or layout that they
|
||||
process. Most of the time, this cost is minimal and doesn’t noticeably affect
|
||||
performance. However, it can be greater when an app adds or removes View
|
||||
objects, such as when a {@link android.support.v7.widget.RecyclerView}
|
||||
object recycles them or reuses them. The
|
||||
cost can also be higher if a {@link android.view.View} object needs to consider
|
||||
resizing to main its constraints: For example, if your app calls
|
||||
{@link android.widget.TextView#setText(char[], int, int) SetText()} on a
|
||||
{@link android.view.View} object that wraps text, the
|
||||
{@link android.view.View} may need to resize.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If cases like these take too long, they can prevent a frame from rendering
|
||||
within the allowed 16ms, so that frames are dropped, and animation becomes
|
||||
janky.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Because you cannot move these operations to a worker thread—your app must
|
||||
process them on the main thread—your best bet is to optimize them so that
|
||||
they can take as little time as possible.
|
||||
</p>
|
||||
|
||||
<h3 id="managing">Managing complexity: layouts matter</h3>
|
||||
|
||||
<p>
|
||||
Android <a
|
||||
href="{@docRoot}guide/topics/ui/declaring-layout.html">Layouts</a>
|
||||
allow you to nest UI objects in the view hierarchy. This nesting can also impose
|
||||
a layout cost. When your app processes an object for layout, the app performs
|
||||
the same process on all children of the layout as well. For a complicated
|
||||
layout, sometimes a cost only arises the first time the system computes the
|
||||
layout. For instance, when your app recycles a complex list item in a
|
||||
{@link android.support.v7.widget.RecyclerView} object, the
|
||||
system needs to lay out all of the objects. In another example, trivial changes
|
||||
can propagate up the chain toward the parent
|
||||
until they reach an object that doesn’t affect the size of the parent.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The most common case in which layout takes an especially long time is when
|
||||
hierarchies of {@link android.view.View} objects are nested within one another. Each nested layout
|
||||
object adds cost to the layout stage. The flatter your hierarchy, the less
|
||||
time that it takes for the layout stage to complete.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you are using the {@link android.widget.RelativeLayout} class, you may be able to achieve the same
|
||||
effect, at lower cost, by using nested, unweighted
|
||||
{@link android.widget.LinearLayout} views instead. Additionally, if your app
|
||||
targets Android N (API level 24), it is likely that
|
||||
you can use a special layout editor to create a <a
|
||||
href="http://tools.android.com/tech-docs/layout-editor">{@code ConstraintLayout}</a>
|
||||
object instead of {@link android.widget.RelativeLayout}. Doing so allows you
|
||||
to avoid many of the issues this section
|
||||
describes. The <a
|
||||
href="http://tools.android.com/tech-docs/layout-editor">{@code ConstraintLayout}</a>
|
||||
class offers similar layout control, but
|
||||
with much-improved performance. This class uses its own constraint-solving
|
||||
system to resolve relationships between views in a very different way from
|
||||
standard layouts.
|
||||
</p>
|
||||
|
||||
<h3 id="double">Double Taxation</h3>
|
||||
|
||||
<p>
|
||||
Typically, the framework executes the <a
|
||||
href="{@docRoot}guide/topics/ui/declaring-layout.html">layout</a>
|
||||
or measure stage in a single pass and quite quickly. However, with some more
|
||||
complicated layout cases, the framework may have to iterate multiple times on
|
||||
the layout or measure stage before ultimately positioning the elements. Having
|
||||
to perform more than one layout-and-measure iteration is referred to as
|
||||
<em>double taxation.</em>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For example, when you use the {@link android.widget.RelativeLayout} container, which allows you to
|
||||
position {@link android.view.View} objects with respect to the positions of other {@link android.view.View} objects, the
|
||||
framework performs the following actions:
|
||||
</p>
|
||||
|
||||
<ol style="1">
|
||||
<li>Executes a layout-and-measure pass, during which the framework calculates
|
||||
each child object’s position and size, based on each child’s request.
|
||||
<li>Uses this data, also taking object weights into account, to figure out the
|
||||
proper position of correlated views.
|
||||
<li>Performs a second layout pass to finalize the objects’ positions.
|
||||
<li>Goes on to the next stage of the rendering process.</li></ol>
|
||||
|
||||
<p>
|
||||
The more levels your view hierarchy has, the greater the potential performance
|
||||
penalty.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Containers other than {@link android.widget.RelativeLayout} may also give rise to double taxation. For
|
||||
example:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>A {@link android.widget.LinearLayout} view
|
||||
could result in a double layout-and-measure pass if you make it horizontal.
|
||||
A double layout-and-measure pass may also occur in a vertical orientation if you
|
||||
add <a
|
||||
href="{@docRoot}reference/android/widget/LinearLayout.html#attr_android:measureWithLargestChild">measureWithLargestChild</a>,
|
||||
in which case the framework may need to do a second pass to resolve the proper
|
||||
sizes of objects.
|
||||
<li>The {@link android.widget.GridLayout}
|
||||
has a similar issue. While this container also allows relative positioning, it
|
||||
normally avoids double taxation by pre-processing the positional relationships
|
||||
among child views. However, if the layout uses weights or fill with the
|
||||
{@link android.view.Gravity} class, the
|
||||
benefit of that preprocessing is lost, and the framework may have to perform
|
||||
multiple passes if it the container were a {@link android.widget.RelativeLayout}.</li>
|
||||
</ul>
|
||||
<p>
|
||||
Multiple layout-and-measure passes are not, in themselves, a performance burden.
|
||||
But they can become so if they’re in the wrong spot. You should be wary of
|
||||
situations where one of the following conditions applies to your container:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>It is a root element in your view hierarchy.
|
||||
<li>It has a deep view hierarchy beneath it.
|
||||
<li>It is nested.
|
||||
<li>There are many instances of it populating the screen, similar to children
|
||||
in a {@link android.widget.ListView} object.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="dx">Diagnosing View Hierarchy Issues</h2>
|
||||
|
||||
<p>
|
||||
Layout performance is a complex problem with many facets. There are a couple of
|
||||
tools that can give you solid indications about where performance bottlenecks
|
||||
are occurring. A few other tools provide less definitive information, but can
|
||||
also provide helpful hints.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<h3 id="systrace">Systrace</h3>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
One tool that provides excellent data about performance is <a
|
||||
href="{@docRoot}studio/profile/systrace.html">Systrace</a>,
|
||||
which is built into Android Studio. The Systrace tool allows you to collect and
|
||||
inspect timing information across an entire Android device, allowing you to see
|
||||
specifically where performance bottlenecks arise. For more information about
|
||||
Systrace, see <a href=”{docRoot}<a href="{@docRoot}studio/profile/systrace.html">
|
||||
Analyze UI Performance with Systrace</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="profile">Profile GPU rendering</h3>
|
||||
|
||||
<p>
|
||||
The other tool most likely to provide you with concrete information about
|
||||
performance bottlenecks is the on-device <a
|
||||
href="{@docRoot}studio/profile/dev-options-rendering.html">
|
||||
Profile GPU rendering</a> tool, available on devices powered by Android 6.0 (API
|
||||
level 23) and later. This tool allows you to see how long the layout-and-measurestage is
|
||||
taking for <a href="https://youtu.be/erGJw8WDV74">each frame
|
||||
of rendering</a>. This data can help you diagnose runtime performance issues,
|
||||
and help you determine what, if any layout-and-measure issues you need to
|
||||
address.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In its graphical representation of the data it captures, <a
|
||||
href="{@docRoot}studio/profile/dev-options-rendering.html">Profile
|
||||
GPU rendering</a> uses the color blue to represent layout time. For more
|
||||
information about how to use this tool, see <a
|
||||
href="{@docRoot}studio/profile/dev-options-rendering.html">Profile
|
||||
GPU Rendering Walkthrough.</a>
|
||||
</p>
|
||||
|
||||
<h3 id="lint">Lint</h3>
|
||||
|
||||
<p>
|
||||
AndroidStudio’s <a
|
||||
href="{@docRoot}studio/write/lint.html">Lint</a> tool can
|
||||
help you gain a sense of inefficiencies in the view hierarchy. To use this tool,
|
||||
select <strong>Analyze > Inspect Code</strong>, as shown in Figure 1.
|
||||
</p>
|
||||
|
||||
<img src="{@docRoot}topic/performance/images/lint-inspect-code.png">
|
||||
<p class="img-caption">
|
||||
<strong>Figure 1.</strong> Locating <strong>Inspect Code</strong> in the
|
||||
Android Studio.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Information about various layout items appears under
|
||||
<em>Android > Lint > Performance</em>. To see more detail,
|
||||
you can click on each item to expand it, and see more
|
||||
information in the pane on the right side of the screen.
|
||||
Figure 2 shows an example of such a display.
|
||||
</p>
|
||||
|
||||
<img src="{@docRoot}topic/performance/images/lint-display.png">
|
||||
<p class="img-caption">
|
||||
<strong>Figure 2.</strong> Viewing information about specific
|
||||
issues that the lint tool has identified.
|
||||
</p>
|
||||
|
||||
|
||||
<p>
|
||||
Clicking on one of these items reveals, in the pane to the right, the problem
|
||||
associated with that item.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To understand more about specific topics and issues in this area, see the <a
|
||||
href="{@docRoot}studio/write/lint.html">Lint
|
||||
</a>documentation.
|
||||
</p>
|
||||
|
||||
<h3 id="hv">Hierarchy Viewer</h3>
|
||||
|
||||
<p>
|
||||
Android Studio’s <a
|
||||
href="{@docRoot}studio/profile/hierarchy-viewer.html">Hierarchy
|
||||
Viewer</a> tool provides a visual representation of your app’s view hierarchy.
|
||||
It is a good way to navigate the hierarchy of your app, providing a clear visual
|
||||
representation of a particular view’s parent chain, and allowing you to inspect
|
||||
the layouts that your app constructs.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The views that Hierarchy Viewer presents can also help identify performance
|
||||
problems arising from double taxation. It can also provide an easy way for you
|
||||
to identify deep chains of nested layouts, or layout areas with a large amount
|
||||
of nested children, another potential source of performance costs. In these
|
||||
scenarios, the layout-and-measure stages can be particularly costly,
|
||||
resulting in performance issues.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can also can get a sense of relative time taken by layout-and-measure
|
||||
operations by clicking the “profile node” button.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For more information about Hierarchy Viewer, see <a
|
||||
href="{@docRoot}studio/profile/optimize-ui.html#HierarchyViewer">Optimizing
|
||||
Your UI</a>.
|
||||
</p>
|
||||
|
||||
<h2 id="solving">Solving View Hierarchy Issues</h2>
|
||||
|
||||
<p>
|
||||
The fundamental concept behind solving performance problems that arise from view
|
||||
hierarchies is simple in concept, but more difficult in practice. Preventing
|
||||
view hierarchies from imposing performance penalties encompasses the dual goals
|
||||
of flattening your view hierarchy and reducing double taxation. This section
|
||||
discusses some strategies for pursuing these goals.
|
||||
</p>
|
||||
|
||||
<h3 id="removing">Removing redundant nested layouts</h3>
|
||||
|
||||
<p>
|
||||
Developers often use more nested layouts than necessary. For example, a
|
||||
{@link android.widget.RelativeLayout} container might contain a single child that is also a
|
||||
{@link android.widget.RelativeLayout} container. This nesting amounts to redundancy, and adds
|
||||
unnecessary cost to the view hierarchy.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Lint can often flag this problem for you, reducing debugging time.
|
||||
</p>
|
||||
|
||||
<h3>Adopting Merge/Include </h3>
|
||||
<p>
|
||||
One frequent cause of redundant nested layouts is the <a
|
||||
href="{@docRoot}training/improving-layouts/reusing-layouts.html">
|
||||
<include>
|
||||
tag</a>. For example, you may define a re-usable layout as follows:
|
||||
</p>
|
||||
|
||||
<pre class="prettyprint">
|
||||
<LinearLayout>
|
||||
<!-- some stuff here -->
|
||||
</LinearLayout>
|
||||
</pre>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
And then an include tag to add this item to the parent container:
|
||||
</p>
|
||||
|
||||
<pre class="prettyprint">
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/app_bg"
|
||||
android:gravity="center_horizontal">
|
||||
|
||||
<include layout="@layout/titlebar"/>
|
||||
|
||||
<TextView android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/hello"
|
||||
android:padding="10dp" />
|
||||
|
||||
...
|
||||
|
||||
</LinearLayout>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The include unnecessarily nests the first layout within the second layout.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <a
|
||||
href="{@docRoot}training/improving-layouts/reusing-layouts.html#Merge">merge
|
||||
</a>tag can help prevent this issue. For information about this tag, see <a
|
||||
href="{@docRoot}training/improving-layouts/reusing-layouts.html#Merge">Re-using
|
||||
Layouts with <include></a>.
|
||||
</p>
|
||||
|
||||
<h3 id="cheaper">Adopting a cheaper layout</h3>
|
||||
|
||||
<p>
|
||||
You may not be able to adjust your existing layout scheme so that it doesn’t
|
||||
contain redundant layouts. In certain cases, the only solution may be to flatten
|
||||
your hierarchy by switching over to an entirely different layout type.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For example, you may find that a {@link android.widget.TableLayout}
|
||||
provides the same functionality as a more complex layout with many
|
||||
positional dependencies. In the N release of Android, the
|
||||
<a
|
||||
href="http://tools.android.com/tech-docs/layout-editor">{@code ConstraintLayout}</a> class provides similar functionality to
|
||||
{@link android.widget.RelativeLayout}, but at a significantly lower cost.
|
||||
</p>
|
||||
Reference in New Issue
Block a user