Merge "docs: add Android U class for "Improving Performance of Layouts"" into ics-mr0

This commit is contained in:
Scott Main
2011-12-14 14:53:04 -08:00
committed by Android (Google) Code Review
10 changed files with 574 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -0,0 +1,58 @@
page.title=Improving Performance of Layouts
trainingnavtop=true
startpage=true
next.title=Optimizing Layout
next.link=optimizing-layout.html
@jd:body
<div id="tb-wrapper">
<div id="tb">
<!-- Required platform, tools, add-ons, devices, knowledge, etc. -->
<h2>Dependencies and prerequisites</h2>
<ul>
<li>Android 1.5 (API Level 3) or higher</li>
</ul>
<!-- related docs (NOT javadocs) -->
<h2>You should also read</h2>
<ul>
<li><a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a></li>
</ul>
</div>
</div>
<p>Layouts are a key part of Android applications that directly affect the user experience. If
implemented poorly, your layout can lead to a memory hungry application with slow UIs. The Android
SDK includes tools to help you identify problems in your layout performance, which when combined the
lessons here, you will be able to implement smooth scrolling interfaces with a minimum memory
footprint.</p>
<h2>Lessons</h2>
<dl>
<dt><b><a href="optimizing-layout.html">Optimizing Layout Hierarchies</a></b></dt>
<dd>In the same way a complex web page can slow down load time, your layout hierarchy
if too complex can also cause performance problems. This lesson shows how you can use SDK tools
to inspect your layout and discover performance bottlenecks.</dd>
<dt><b><a href="reusing-layouts.html">Re-using Layouts with &lt;include/&gt;</a></b></dt>
<dd>If your application UI repeats certain layout constructs in multiple places, this lesson
shows you how to create efficient, re-usable layout constructs, then include them in the appropriate
UI layouts.</dd>
<dt><b><a href="loading-ondemand.html">Loading Views On Demand</a></b></dt>
<dd>Beyond simply including one layout component within another layout, you might want to
make the included layout visible only when it's needed, sometime after the activity is running.
This lesson shows how you can improve your layout's initialization performance by loading
portions of your layout on demand.</dd>
<dt><b><a href="smooth-scrolling.html">Making ListView Scrolling Smooth</a></b></dt>
<dd>If you've built an instance of {@link android.widget.ListView} that contains complex or
data-heavy content in each list item, the scroll performance of the list might suffer. This
lesson provides some tips about how you can make your scrolling performance more smooth.</dd>
</dl>

View File

@@ -0,0 +1,86 @@
page.title=Loading Views On Demand
parent.title=Improving Performance of Layouts
parent.link=index.html
trainingnavtop=true
previous.title=Re-using Layouts with &lt;include/&gt;
previous.link=reusing-layouts.html
next.title=Making ListView Scrolling Smooth
next.link=smooth-scrolling.html
@jd:body
<div id="tb-wrapper">
<div id="tb">
<!-- table of contents -->
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#ViewStub">Define a ViewStub</a></li>
<li><a href="#Load">Load the ViewStub Layout</a></li>
</ol>
<!-- other docs (NOT javadocs) -->
<h2>You should also read</h2>
<ul>
<li><a href="{@docRoot}resources/articles/layout-tricks-stubs.html">Using ViewStubs</a></li>
</ul>
</div>
</div>
<p>Sometimes your layout might require complex views that are rarely used. Whether
they are item details, progress indicators, or undo messages, you can reduce memory usage and speed
up rendering by loading the views only when they are needed.</p>
<h2 id="ViewStub">Define a ViewStub</h2>
<p>{@link android.view.ViewStub} is a lightweight view with no dimension and doesnt draw anything
or participate in the layout. As such, it's cheap to inflate and cheap to leave in a view hierarchy.
Each {@link android.view.ViewStub} simply needs to include the {@code android:layout} attribute to
specify the layout to inflate.</p>
<p>The following {@link android.view.ViewStub} is for a translucent progress bar overlay. It should
be visible only when new items are being imported into the application.</p>
<pre>
&lt;ViewStub
android:id="@+id/stub_import"
android:inflatedId="@+id/panel_import"
android:layout="@layout/progress_overlay"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom" /&gt;
</pre>
<h2 id="Load">Load the ViewStub Layout</h2>
<p>When you want to load the layout specified by the {@link android.view.ViewStub}, either set it
visible by calling {@link android.view.View#setVisibility setVisibility(View.VISIBLE)} or call
{@link android.view.ViewStub#inflate()}.</p>
<pre>
((ViewStub) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);
// or
View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();
</pre>
<p class="note"><strong>Note:</strong> The {@link android.view.ViewStub#inflate()} method returns
the inflated {@link android.view.View} once complete. so you don't need to call {@link
android.app.Activity#findViewById findViewById()} if you need to interact with the layout.</p>
<p>Once visible/inflated, the {@link android.view.ViewStub} element is no longer part of the view
hierarchy. It is replaced by the inflated layout and the ID for the root view of that layout is
the one specified by the {@code android:inflatedId} attribute of the ViewStub. (The ID {@code
android:id} specified for the {@link android.view.ViewStub} is valid only until the {@link
android.view.ViewStub} layout is visible/inflated.)</p>
<p class="note"><strong>Note:</strong> One drawback of {@link android.view.ViewStub} is that it
doesnt currently support the {@code &lt;merge/&gt;} tag in the layouts to be inflated.</p>

View File

@@ -0,0 +1,156 @@
page.title=Optimizing Layout Hierarchies
parent.title=Improving Performance of Layouts
parent.link=index.html
trainingnavtop=true
next.title=Re-using Layouts with &lt;include/&gt;
next.link=reusing-layouts.html
@jd:body
<div id="tb-wrapper">
<div id="tb">
<!-- table of contents -->
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#Inspect">Inspect Your Layout</a></li>
<li><a href="#Revise">Revise Your Layout</a></li>
<li><a href="#Layoutopt">Use Layoutopt</a></li>
</ol>
<!-- other docs (NOT javadocs) -->
<h2>You should also read</h2>
<ul>
<li><a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a></li>
<li><a
href="{@docRoot}guide/topics/resources/layout-resource.html#include- element">Layout
Resource</a></li>
</ul>
</div>
</div>
<p>It is a common misconception that using the basic layout structures leads to the most efficient
layouts. However, each widget and layout you add to your application requires initialization,
layout, and drawing. For example, using nested instances of {@link android.widget.LinearLayout} can
lead to an excessively deep view hierarchy. Furthermore, nesting several instances of {@link
android.widget.LinearLayout} that use the {@code layout_weight} parameter can be especially
expensive as each child needs to be measured twice. This is particularly important when the layout
is inflated repeatedly, such as when used in a {@link android.widget.ListView} or {@link
android.widget.GridView}.</p>
<p>In this lesson you'll learn to use <a
href="{@docRoot}guide/developing/tools/hierarchy-viewer.html">Heirachy Viewer</a> and <a
href="{@docRoot}guide/developing/tools/layoutopt.html">Layoutopt</a> to examine and optimize your
layout.</p>
<h2 id="Inspect">Inspect Your Layout</h2>
<p>The Android SDK tools include a tool called <a
href="{@docRoot}guide/developing/tools/hierarchy-viewer.html">Heirachy Viewer</a> that allows
you to analyze your layout while your application is running. Using this tool helps you discover
bottlenecks in the layout performance.</p>
<p>Hierarchy Viewer works by allowing you to select running processes on a connected device or
emulator, then display the layout tree. The traffic lights on each block represent its Measure,
Layout and Draw performance, helping you identify potential issues.</p>
<p>For example, figure 1 shows a layout that's used as an item in a {@link
android.widget.ListView}. This layout shows a small bitmap image on the left and two stacked items
of text on the right. It is especially important that layouts that will be inflated multiple
times&mdash;such as this one&mdash;are optimized as the performance
benefits will be multiplied.</p>
<img src="{@docRoot}images/training/layout-listitem.png" alt="" />
<p class="img-caption"><strong>Figure 1.</strong> Conceptual layout for an item in a {@link
android.widget.ListView}.</p>
<p>The {@code hierarchyviewer} tool is available in {@code &lt;sdk&gt;/tools/}. When opened,
the Hierarchy Viewer shows a list of available devices and its running components. Click
<strong>Load View Hierarchy</strong> to view the layout hierarchy of the selected component. For
example, figure 2 shows the layout for the list item illustrated by figure 1.</p>
<div style="float:left;width:455px">
<img src="{@docRoot}images/training/hierarchy-linearlayout.png" alt="" />
<p class="img-caption"><strong>Figure 2.</strong> Layout hierarchy for the layout in figure 1,
using nested instances of {@link android.widget.LinearLayout}.</p>
</div>
<div style="float:left;width:155px;margin-left:2em">
<img src="{@docRoot}images/training/hierarchy-layouttimes.png" alt="" />
<p class="img-caption"><strong>Figure 3.</strong> Clicking a hierarchy node shows its
performance times.</p>
</div>
<p style="clear:left">In figure 2, you can see there is a 3-level hierarchy with some problems
laying out the text items. Clicking on the items shows the time taken for each stage of the process
(figure 3). It becomes clear which items are taking the longest to measure, layout, and render, and
where you should spend time optimizing.</p>
<p>The timings for rendering a complete list item using this layout are:</p>
<ul>
<li>Measure: 0.977ms</li>
<li>Layout: 0.167ms</li>
<li>Draw: 2.717ms</li>
</ul>
<h2 id="Revise">Revise Your Layout</h2>
<p>Because the layout performance above slows down due to a nested {@link
android.widget.LinearLayout}, the performance might improve by flattening the layout&mdash;make
the layout shallow and wide, rather than narrow and deep. A {@link android.widget.RelativeLayout} as
the root node allows for such layouts. So, when this design is converted to use {@link
android.widget.RelativeLayout}, you can see that the layout becomes a 2-level hierarchy. Inspection
of the new layout looks like this:</p>
<img src="{@docRoot}images/training/hierarchy-relativelayout.png" alt="" />
<p class="img-caption"><strong>Figure 4.</strong> Layout hierarchy for the layout in figure 1,
using {@link android.widget.RelativeLayout}.</p>
<p>Now rendering a list item takes:</p>
<ul>
<li>Measure: 0.598ms</li>
<li>Layout: 0.110ms</li>
<li>Draw: 2.146ms</li>
</ul>
<p>Might seem like a small improvement, but this time is multiplied several times because this
layout is used for every item in a list.</p>
<p>Most of this time difference is due to the use of {@code layout_weight} in the {@link
android.widget.LinearLayout} design, which can slow down the speed of measurement. It is just one
example of how each layout has appropriate uses and you should carefully consider whether using
layout weight is necessary.</p>
<h2 id="Layoutopt">Use Layoutopt</h2>
<p>It is always good practice to also run the <a
href="{@docRoot}guide/developing/tools/layoutopt.html">layoutopt</a> tool on your final layout files
to search for places in your view hierarchy that may be optimized. Layoutopt is also in your SDK
{@code tools/} directory and takes a layout directory name or a space-separated list of layout files
that you'd like to inspect.</p>
<p>When you run {@code layoutopt} on a layout file, it prints a line number for each issue found, a
description of the issue, and for some types of issues it also suggests a resolution. For
example:</p>
<pre class="no-pretty-print classic">
$ layoutopt samples/
samples/compound.xml
7:23 The root-level &lt;FrameLayout/&gt; can be replaced with &lt;merge/&gt;
11:21 This LinearLayout layout or its FrameLayout parent is useless
samples/simple.xml
7:7 The root-level &lt;FrameLayout/&gt; can be replaced with &lt;merge/&gt;
</pre>
<p>After you apply the suggested layout optimizations, run Hierarchy Viewer again to inspect the
performance changes.</p>

View File

@@ -0,0 +1,150 @@
page.title=Re-using Layouts with &lt;include/&gt;
parent.title=Improving Performance of Layouts
parent.link=index.html
trainingnavtop=true
previous.title=Optimizing Layout Hierarchies
previous.link=optimizing-layout.html
next.title=Loading Views On Demand
next.link=loading-ondemand.html
@jd:body
<div id="tb-wrapper">
<div id="tb">
<!-- table of contents -->
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#Create">Create a Re-usable Layout</a></li>
<li><a href="#Include">Use the &lt;include&gt; Tag</a></li>
<li><a href="#Merge">Use the &lt;merge&gt; Tag</a></li>
</ol>
<!-- other docs (NOT javadocs) -->
<h2>You should also read</h2>
<ul>
<li><a href="{@docRoot}resources/articles/layout-tricks-reuse.html">Creating Reusable UI
Components</a></li>
<li><a href="{@docRoot}resources/articles/layout-tricks-merge.html">Merging Layouts</a></li>
<li><a
href="{@docRoot}guide/topics/resources/layout-resource.html#include-element">Layout
Resource</a></li>
</ul>
</div>
</div>
<p>Although Android offers a variety of widgets to provide small and re-usable interactive elements,
you might also need to re-use larger components that require a special layout. To efficiently
re-use complete layouts, you can use the {@code &lt;include/&gt;} and {@code &lt;merge/&gt;} tags
to embed another layout inside the current layout.</p>
<p>Reusing layouts is particularly powerful as it allows you create reusable complex layouts. For
example, a yes/no button panel, or custom progress bar with description text.
It also means that any elements of your application that are common across multiple layouts can be
extracted, managed separately, then included in each layout. So while
you can create individual UI components by writing a custom {@link android.view.View}, you can
do it even more easily by re-using a layout file.</p>
<h2 id="Create">Create a Re-usable Layout</h2>
<p>If you already know the layout that you want to re-use, create a new XML file and define the
layout. For example, here's a layout from the G-Kenya codelab that defines a title bar to be
included in each activity (<code>titlebar.xml</code>):</p>
<pre>
&lt;FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width=”match_parent”
android:layout_height="wrap_content"
android:background="&#64;color/titlebar_bg">
&lt;ImageView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="&#64;drawable/gafricalogo" />
&lt;/FrameLayout>
</pre>
<p>The root {@link android.view.View} should be exactly how you'd like it to appear in each
layout to which you add this layout.</p>
<h2 id="Include">Use the &lt;include&gt; Tag</h2>
<p>Inside the layout to which you want to add the re-usable component, add the {@code
&lt;include/&gt;} tag. For example, here's a layout from the
G-Kenya codelab that includes the title bar from above:</p>
<p>Here's the layout file:</p>
<pre>
&lt;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="&#64;color/app_bg"
android:gravity="center_horizontal">
<strong>&lt;include layout="&#64;layout/titlebar"/></strong>
&lt;TextView android:layout_width=”match_parent”
android:layout_height="wrap_content"
android:text="&#64;string/hello"
android:padding="10dp" />
...
&lt;/LinearLayout>
</pre>
<p>You can also override all the layout parameters (any {@code android:layout_*} attributes) of the
included layout's root view by specifying them in the {@code &lt;include/&gt;} tag. For
example:</p>
<pre>
&lt;include android:id=”&#64;+id/news_title”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
layout=”@layout/title”/>
</pre>
<h2 id="Merge">Use the &lt;merge&gt; Tag</h2>
<p>The {@code &lt;merge />} tag helps eliminate redundant view groups in your view hierarchy
when including one layout within another. For example, if your main layout is a vertical {@link
android.widget.LinearLayout} in which two consecutive views can be
re-used in multiple layouts, then the re-usable layout in which you place the two views requires its
own root view. However, using another {@link android.widget.LinearLayout} as the root for the
re-usable layout would result in a vertical {@link android.widget.LinearLayout} inside a
vertical {@link android.widget.LinearLayout}. The nested {@link android.widget.LinearLayout}
serves no real purpose other than to slow down your UI performance.</p>
<p>To avoid including such a redundant view group, you can instead use the
{@code &lt;merge&gt;} element as the root view for the re-usable layout. For example:</p>
<pre>
&lt;merge xmlns:android="http://schemas.android.com/apk/res/android">
&lt;Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/add"/>
&lt;Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/delete"/>
&lt;/merge>
</pre>
<p>Now, when you include this layout in another layout (using the {@code &lt;include/&gt;} tag), the
system ignores the {@code &lt;merge&gt;} element and places the two buttons directly in the
layout, in place of the {@code &lt;include/&gt;} tag.</p>

View File

@@ -0,0 +1,124 @@
page.title=Making ListView Scrolling Smooth
parent.title=Optimizing Performance of Layouts
parent.link=index.html
trainingnavtop=true
previous.title=Loading Views On Demand
previous.link=loading-ondemand.html
@jd:body
<div id="tb-wrapper">
<div id="tb">
<!-- table of contents -->
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#AsyncTask">Use a Background Thread</a></li>
<li><a href="#ViewHolder">Hold View Objects in a View Holder</a></li>
</ol>
<!-- other docs (NOT javadocs) -->
<h2>You should also read</h2>
<ul>
<li><a href="{@docRoot}resources/articles/listview-backgrounds.html">ListView
Backgrounds: An Optimization</a></li>
</ul>
</div>
</div>
<p>The key to a smoothly scrolling {@link android.widget.ListView} is to keep the applications main
thread (the UI thread) free from heavy processing. Ensure you do any disk access, network access, or
SQL access in a separate thread. To test the status of your app, you can enable {@link
android.os.StrictMode}.</p>
<h2 id="AsyncTask">Use a Background Thread</h2>
<p>Using a background thread ("worker thread") removes strain from the main thread so it can focus
on drawing the UI. In many cases, using {@link android.os.AsyncTask} provides a simple way to
perform your work outside the main thread. {@link android.os.AsyncTask} automatically queues up all
the {@link android.os.AsyncTask#execute execute()} requests and performs them serially. This
behavior is global to a particular process and means you dont need to worry about creating your
own thread pool.</p>
<p>In the sample code below, an {@link android.os.AsyncTask} is used to load
images in a background thread, then apply them to the UI once finished. It also shows a
progress spinner in place of the images while they are loading.</p>
<pre>
// Using an AsyncTask to load the slow images in a background thread
new AsyncTask&lt;ViewHolder, Void, Bitmap>() {
private ViewHolder v;
&#64;Override
protected Bitmap doInBackground(ViewHolder... params) {
v = params[0];
return mFakeImageLoader.getImage();
}
&#64;Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
if (v.position == position) {
// If this item hasn't been recycled already, hide the
// progress and set and show the image
v.progress.setVisibility(View.GONE);
v.icon.setVisibility(View.VISIBLE);
v.icon.setImageBitmap(result);
}
}
}.execute(holder);
</pre>
<p>Beginning with Android 3.0 (API level 11), an extra feature is available in {@link
android.os.AsyncTask} so you can enable it to run across multiple processor cores. Instead of
calling {@link android.os.AsyncTask#execute execute()} you can specify {@link
android.os.AsyncTask#executeOnExecutor executeOnExecutor()} and multiple requests can be executed at
the same time depending on the number of cores available.</p>
<h2 id="ViewHolder">Hold View Objects in a View Holder</h2>
<p>Your code might call {@link android.app.Activity#findViewById findViewById()} frequently
during the scrolling of {@link android.widget.ListView}, which can slow down performance. Even when
the {@link
android.widget.Adapter} returns an inflated view for recycling, you still need to look up the
elements
and update them. A way around repeated use of {@link android.app.Activity#findViewById
findViewById()} is to use the "view holder" design pattern.</p>
<p>A {@code ViewHolder} object stores each of the component views inside the tag field of the
Layout, so you can immediately access them without the need to look them up repeatedly. First, you
need to create a class to hold your exact set of views. For example:</p>
<pre>
static class ViewHolder {
TextView text;
TextView timestamp;
ImageView icon;
ProgressBar progress;
int position;
}
</pre>
<p>Then populate the {@code ViewHolder} and store it inside the layout.</p>
<pre>
ViewHolder holder = new ViewHolder();
holder.icon = (ImageView) convertView.findViewById(R.id.listitem_image);
holder.text = (TextView) convertView.findViewById(R.id.listitem_text);
holder.timestamp = (TextView) convertView.findViewById(R.id.listitem_timestamp);
holder.progress = (ProgressBar) convertView.findViewById(R.id.progress_spinner);
convertView.setTag(holder);
</pre>
<p>Now you can easily access each view without the need for the look-up, saving valuable processor
cycles.</p>