diff --git a/docs/html/images/training/hierarchy-layouttimes.png b/docs/html/images/training/hierarchy-layouttimes.png new file mode 100644 index 0000000000000..423f1af5150bd Binary files /dev/null and b/docs/html/images/training/hierarchy-layouttimes.png differ diff --git a/docs/html/images/training/hierarchy-linearlayout.png b/docs/html/images/training/hierarchy-linearlayout.png new file mode 100644 index 0000000000000..cac4caef0e218 Binary files /dev/null and b/docs/html/images/training/hierarchy-linearlayout.png differ diff --git a/docs/html/images/training/hierarchy-relativelayout.png b/docs/html/images/training/hierarchy-relativelayout.png new file mode 100644 index 0000000000000..b3408e58b9d8e Binary files /dev/null and b/docs/html/images/training/hierarchy-relativelayout.png differ diff --git a/docs/html/images/training/import-progress.png b/docs/html/images/training/import-progress.png new file mode 100644 index 0000000000000..bbb689b51d4e4 Binary files /dev/null and b/docs/html/images/training/import-progress.png differ diff --git a/docs/html/images/training/layout-listitem.png b/docs/html/images/training/layout-listitem.png new file mode 100644 index 0000000000000..9cb241df6d455 Binary files /dev/null and b/docs/html/images/training/layout-listitem.png differ diff --git a/docs/html/training/improving-layouts/index.jd b/docs/html/training/improving-layouts/index.jd new file mode 100644 index 0000000000000..4cc6963198175 --- /dev/null +++ b/docs/html/training/improving-layouts/index.jd @@ -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 + +
+
+ + +

Dependencies and prerequisites

+ + + +

You should also read

+ + +
+
+ + + +

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.

+ + + +

Lessons

+ +
+
Optimizing Layout Hierarchies
+
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.
+
Re-using Layouts with <include/>
+
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.
+
Loading Views On Demand
+
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.
+
Making ListView Scrolling Smooth
+
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.
+
\ No newline at end of file diff --git a/docs/html/training/improving-layouts/loading-ondemand.jd b/docs/html/training/improving-layouts/loading-ondemand.jd new file mode 100644 index 0000000000000..659b1ec3cd7d3 --- /dev/null +++ b/docs/html/training/improving-layouts/loading-ondemand.jd @@ -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 <include/> +previous.link=reusing-layouts.html +next.title=Making ListView Scrolling Smooth +next.link=smooth-scrolling.html + +@jd:body + + +
+
+ + +

This lesson teaches you to

+
    +
  1. Define a ViewStub
  2. +
  3. Load the ViewStub Layout
  4. +
+ + +

You should also read

+ + +
+
+ + +

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.

+ + +

Define a ViewStub

+ +

{@link android.view.ViewStub} is a lightweight view with no dimension and doesn’t 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.

+ +

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.

+ +
+<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" />
+
+ + +

Load the ViewStub Layout

+ +

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()}.

+ +
+((ViewStub) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);
+// or
+View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();
+
+ +

Note: 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.

+ +

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.)

+ +

Note: One drawback of {@link android.view.ViewStub} is that it +doesn’t currently support the {@code <merge/>} tag in the layouts to be inflated.

+ + + diff --git a/docs/html/training/improving-layouts/optimizing-layout.jd b/docs/html/training/improving-layouts/optimizing-layout.jd new file mode 100644 index 0000000000000..3237780b88e59 --- /dev/null +++ b/docs/html/training/improving-layouts/optimizing-layout.jd @@ -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 <include/> +next.link=reusing-layouts.html + +@jd:body + + + +
+
+ + +

This lesson teaches you to

+
    +
  1. Inspect Your Layout
  2. +
  3. Revise Your Layout
  4. +
  5. Use Layoutopt
  6. +
+ + +

You should also read

+ + +
+
+ + +

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}.

+ +

In this lesson you'll learn to use Heirachy Viewer and Layoutopt to examine and optimize your +layout.

+ + + +

Inspect Your Layout

+ +

The Android SDK tools include a tool called Heirachy Viewer that allows +you to analyze your layout while your application is running. Using this tool helps you discover +bottlenecks in the layout performance.

+ +

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.

+ +

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—such as this one—are optimized as the performance +benefits will be multiplied.

+ + +

Figure 1. Conceptual layout for an item in a {@link +android.widget.ListView}.

+ +

The {@code hierarchyviewer} tool is available in {@code <sdk>/tools/}. When opened, +the Hierarchy Viewer shows a list of available devices and its running components. Click +Load View Hierarchy to view the layout hierarchy of the selected component. For +example, figure 2 shows the layout for the list item illustrated by figure 1.

+ +
+ +

Figure 2. Layout hierarchy for the layout in figure 1, +using nested instances of {@link android.widget.LinearLayout}.

+
+ +
+ +

Figure 3. Clicking a hierarchy node shows its +performance times.

+
+ +

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.

+ +

The timings for rendering a complete list item using this layout are:

+ + + +

Revise Your Layout

+ +

Because the layout performance above slows down due to a nested {@link +android.widget.LinearLayout}, the performance might improve by flattening the layout—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:

+ + +

Figure 4. Layout hierarchy for the layout in figure 1, +using {@link android.widget.RelativeLayout}.

+ +

Now rendering a list item takes:

+ + +

Might seem like a small improvement, but this time is multiplied several times because this +layout is used for every item in a list.

+ +

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.

+ + +

Use Layoutopt

+ +

It is always good practice to also run the layoutopt 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.

+ +

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:

+ +
+$ layoutopt samples/
+samples/compound.xml
+   7:23 The root-level <FrameLayout/> can be replaced with <merge/>
+   11:21 This LinearLayout layout or its FrameLayout parent is useless
+samples/simple.xml
+   7:7 The root-level <FrameLayout/> can be replaced with <merge/>
+
+ +

After you apply the suggested layout optimizations, run Hierarchy Viewer again to inspect the +performance changes.

+ diff --git a/docs/html/training/improving-layouts/reusing-layouts.jd b/docs/html/training/improving-layouts/reusing-layouts.jd new file mode 100644 index 0000000000000..8f9729ac7d68f --- /dev/null +++ b/docs/html/training/improving-layouts/reusing-layouts.jd @@ -0,0 +1,150 @@ +page.title=Re-using Layouts with <include/> +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 + + +
+
+ + +

This lesson teaches you to

+
    +
  1. Create a Re-usable Layout
  2. +
  3. Use the <include> Tag
  4. +
  5. Use the <merge> Tag
  6. +
+ + +

You should also read

+ + +
+
+ + + +

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 <include/>} and {@code <merge/>} tags +to embed another layout inside the current layout.

+ +

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.

+ + +

Create a Re-usable Layout

+ +

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 (titlebar.xml):

+ +
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width=”match_parent”
+    android:layout_height="wrap_content"
+    android:background="@color/titlebar_bg">
+
+    <ImageView android:layout_width="wrap_content"
+               android:layout_height="wrap_content" 
+               android:src="@drawable/gafricalogo" />
+</FrameLayout>
+
+ +

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.

+ + +

Use the <include> Tag

+ +

Inside the layout to which you want to add the re-usable component, add the {@code +<include/>} tag. For example, here's a layout from the +G-Kenya codelab that includes the title bar from above:

+ +

Here's the layout file:

+ +
+<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>
+
+ +

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 <include/>} tag. For +example:

+ +
+<include android:id=”@+id/news_title”
+         android:layout_width=”match_parent”
+         android:layout_height=”match_parent”
+         layout=”@layout/title”/>
+
+ + + +

Use the <merge> Tag

+ +

The {@code <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.

+ +

To avoid including such a redundant view group, you can instead use the +{@code <merge>} element as the root view for the re-usable layout. For example:

+ +
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <Button
+        android:layout_width="fill_parent" 
+        android:layout_height="wrap_content"
+        android:text="@string/add"/>
+
+    <Button
+        android:layout_width="fill_parent" 
+        android:layout_height="wrap_content"
+        android:text="@string/delete"/>
+
+</merge>
+
+ +

Now, when you include this layout in another layout (using the {@code <include/>} tag), the +system ignores the {@code <merge>} element and places the two buttons directly in the +layout, in place of the {@code <include/>} tag.

+ diff --git a/docs/html/training/improving-layouts/smooth-scrolling.jd b/docs/html/training/improving-layouts/smooth-scrolling.jd new file mode 100644 index 0000000000000..bc90dd2fa415d --- /dev/null +++ b/docs/html/training/improving-layouts/smooth-scrolling.jd @@ -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 + + +
+
+ + +

This lesson teaches you to

+
    +
  1. Use a Background Thread
  2. +
  3. Hold View Objects in a View Holder
  4. +
+ + +

You should also read

+ + +
+
+ +

The key to a smoothly scrolling {@link android.widget.ListView} is to keep the application’s 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}.

+ + +

Use a Background Thread

+ +

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 don’t need to worry about creating your +own thread pool.

+ +

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.

+ +
+// Using an AsyncTask to load the slow images in a background thread
+new AsyncTask<ViewHolder, Void, Bitmap>() {
+    private ViewHolder v;
+
+    @Override
+    protected Bitmap doInBackground(ViewHolder... params) {
+        v = params[0];
+        return mFakeImageLoader.getImage();
+    }
+
+    @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);
+
+ +

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.

+ + +

Hold View Objects in a View Holder

+ +

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.

+ +

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:

+ +
+static class ViewHolder {
+  TextView text;
+  TextView timestamp;
+  ImageView icon;
+  ProgressBar progress;
+  int position;
+}
+
+ +

Then populate the {@code ViewHolder} and store it inside the layout.

+ +
+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);
+
+ +

Now you can easily access each view without the need for the look-up, saving valuable processor +cycles.

+ + + + +