Tips for improving the performance of Android ListView

Source: Internet
Author: User

Tips for improving the performance of Android ListView

How does ListView work?

ListView is designed to meet requirements for scalability and high performance. In fact, this means that ListView has the following two requirements:

Create as few views as possible;

Only the child View that is visible on the screen.

Understanding the first point is simple: creating a View and displaying it by layout an xml file is very expensive and resource-consuming. Although the layout file has been compiled and packaged into a binary format for more efficient Syntax Parsing, creating a View still requires a special XML tree and instantiating all views to be responded.

ListView recycles invisible Views, which are usually called "ScrapView (obsolete View)" in the Android source code to solve this problem. This means that developers only need to update the content of each row, instead of creating a View for each individual row layout.

To achieve the second point, when we slide the screen, ListView increases the Views lower than or higher than the current window by using the View recycler, and the Views of the current activity are moved to a recycle pool. In this case, ListView only needs to maintain enough Views in the memory to fill in the layout of the allocated space and some additional recyclable Views, even if your Adapter has hundreds of items suitable. It uses different methods to fill the space between rows, from the top or bottom, depending on how the window changes.

The figure below intuitively shows what happened when you press ListView:

ListView

Through the above introduction, we are familiar with the ListView mechanism, let's continue to the tip section. As described above, while sliding, ListView dynamically creates and recycles a lot of views to make getView () of the Adapter as lightweight as possible. All tips are to use multiple methods to make getView () faster.

View recycling

When a ListView needs to display a new row on the screen, the getView () method is called from its Adapter. As we all know, the getView () method has three parameters: the row location, convertView, and parent ViewGroup.

The convertView parameter is the previously mentioned ScrapView. When ListView requires updating the layout of a row, convertView is a non-null value. Therefore, when the convertView value is not empty, you only need to update the content, instead of re-setting the layout of a new line. GetView () is generally in the following form in the Adapter:

Public View getView (int position, View convertView, ViewGroup parent ){

If (convertView = null ){

ConvertView = mInflater. inflate (R. layout. your_layout, null );

}

TextView text = (TextView) convertView. findViewById (R. id. text );

Text. setText ("Position" + position );

Return convertView;

}

View Holder Template

A common operation of Android is to find an internal View in the layout file. It is usually implemented using a findViewById () View method. The findViewById () method is located in the View tree. Based on a View ID, It is recursively called to find its subtree. Although it is completely normal to use findViewById () in the static UI layout. However, when sliding, ListView calls the getView () in its Adapter very frequently. FindViewById () may affect the performance of ListView sliding, especially when your row layout is complex.

Looking for an internal idea in an inflatable layout is one of the most common operations on Android. This is usually done through a view method named findViewById ). This method is passed through the view tree to find a child using the given ID code. The use of findViewById () in the static UI layout is completely normal, but as you can see, the getView () of the adapter is called frequently during scrolling in the ListView. FindViewById () may perceivably hit ListViews, especially the scrolling performance if your row layout is not trivial.

The View Holder mode reduces the number of times that findViewById () is called in the getView () method of the Adapter. In fact, View Holder is a lightweight internal class used to directly reference all internal views. After creating a View, you can store the View in each row as a tag. In this way, you only need to call findViewById () when creating the layout for the first time (). The following is a sample code of the View Holder template using the preceding method:

Public View getView (int position, View convertView, ViewGroup parent ){

ViewHolder holder;

If (convertView = null ){

ConvertView = mInflater. inflate (R. layout. your_layout, null );

Holder = new ViewHolder ();

Holder. text = (TextView) convertView. findViewById (R. id. text );

ConvertView. setTag (holder );

} Else {

Holder = convertView. getTag ();

}

Holder. text. setText ("Position" + position );

Return convertView;

}

Private static class ViewHolder {

Public TextView text;

}

Asynchronous loading

Most of the time, the Android app displays some multimedia content and video content in each row of the ListView. Using the built-in image resources in getView () in the Adapter does not cause any problems, because it can be stored in the cache of Android. But when you want to show multi-state content from a local disk or network, such as thumbnails and resume images. In this case, you may not want to load them directly in getView () in the Adapter, because the IO process will block the UI thread. If you do this, the ListView looks very choppy.

In a separate thread, if you want to run all the line IO operations or any asynchronous operations with high-load CPU restrictions. The trick is to meet the ListView recycling behavior. For example, if you use AsyncTask to load the data image in getView () in the Adapter, the image View you are loading may be recycled for other places before AsyncTask is completed. Therefore, once the asynchronous operation is completed, a mechanism is required to know if the View is recycled.

To achieve this goal, a simple method is to append some information about the View associated with the row. Then, when the asynchronous operation is completed, check whether the View of the target row is consistent with the View of the identifier. There are many ways to achieve this goal. The following is a simple example:

Public View getView (int position, View convertView,

ViewGroup parent ){

ViewHolder holder;

...

Holder. position = position;

New ThumbnailTask (position, holder)

. ExecuteOnExecutor (AsyncTask. THREAD_POOL_EXECUTOR, null );

Return convertView;

}

Private static class ThumbnailTask extends AsyncTask {

Private int mPosition;

Private ViewHolder mHolder;

Public ThumbnailTask (int position, ViewHolder holder ){

MPosition = position;

MHolder = holder;

}

@ Override

Protected Cursor doInBackground (Void... arg0 ){

// Download bitmap here

}

@ Override

Protected void onPostExecute (Bitmap bitmap ){

If (mHolder. position = mPosition ){

MHolder. thumbnail. setImageBitmap (bitmap );

}

}

}

Private static class ViewHolder {

Public ImageView thumbnail;

Public int position;

}

Human-Computer Interaction knowledge

Loading many resources asynchronously in each row is the only way to achieve a high-performance ListView. However, when sliding the screen, if you start an asynchronous operation in every getView () call, you will waste a lot of resources. Because rows are frequently recycled, most returned results are discarded.

Considering the actual human-computer interaction, in the ListView adapter, no asynchronous operation should be triggered in each row. That is to say, when the ListView has a fling (fast sliding) operation, it makes no sense to start any asynchronous operation. Once the scroll stops or is about to stop, it is time to start displaying the content of each row.

I will not post a sample code here, because there are too many Code involved. Romain Guy writes a classic application: Shelves app, which provides a good example. When the GridView stops sliding, it starts to trigger and asynchronously load the cover resources of the book. Even when sliding, you can also display the content in the cache and balance interaction by using memory cache. This is a good idea!

Above

I strongly recommend that you take a look at Romain Guy and Adam Powell's discussion about ListView, which covers a lot of things in this article. You can see how Pattrn is used in applications.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.