125 lines
4.4 KiB
Plaintext
125 lines
4.4 KiB
Plaintext
page.title=Making ListView Scrolling Smooth
|
||
parent.title=Improving Layout Performance
|
||
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="http://android-developers.blogspot.com/2009/01/why-is-my-list-black-android.html">Why
|
||
is my list black? An Android optimization</a></li>
|
||
</ul>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<p>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}.</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 don’t 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<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);
|
||
</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>
|
||
|
||
|
||
|
||
|
||
|