Analysis on the principle and optimization of ListView in Android, androidlistview

Source: Internet
Author: User

Analysis on the principle and optimization of ListView in Android, androidlistview

Optimization of ListView in Android is often encountered during development or interview. This is not the case. LZ was asked during the recruitment interview for Alibaba 2015 interns. The abused gray-faced face should be summarized.

When it comes to ListView optimization, the first thing that comes to mind is to use convertView and ViewHolder to optimize ListView data loading. Is that all? Actually, it is not. First, to optimize the ListView, you must first understand the data loading principle of the ListView.


The display of the list requires three elements:

1. ListView: used to display the View of the list.

2. Adapter: used to map data to ListView

3. Data: The specific string, image, or basic component to be mapped.

According to the list of adapter types, the list is divided into three types: ArrayAdapter, SimpleAdapter and SimpleCursorAdapter. You can learn how to use these three types of adapters on the official website or Baidu Google, a bunch of demos !!! ArrayAdapter is the simplest and can only display one line of words. SimpleAdapter has the best scalability and Can Customize various effects. SimpleCursorAdapter can be considered as a simple combination of SimpleAdapter on the database, which can easily display the database content in the form of a list.

When using ListView and Adapter, note that Adapter. getView ().

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

This method is used to obtain the View to be displayed at the specified position. The official website is explained as follows:

Get a View that displays the data at the specified position in the data set. You can either create a View manually or inflate it from an XML layout file.


The system wants to draw the ListView. He first uses the getCount () function to get the length of the list to be drawn, and then starts to draw the first line. How can this be drawn? Call the getView () function. In this function, first obtain a View (this is based on the actual situation, if it is a simple display, it is a View, if a custom widget contains many widgets, it is actually a ViewGroup), then instantiate and set each component and its data content and display it. Now, we have drawn this line. Then draw the next line until the painting is complete.

The working principle of ListView is as follows:

ListView requires the adapter to "return a view" (getView) for each item. That is to say, when the ListView starts to be drawn, the system first calls the getCount () function, get the length of the ListView according to the returned value, and then call getView () to draw each item of the ListView row based on the length. If the returned value of getCount () is 0, the list is not displayed for one row. If 1 is returned, only one row is displayed. The number of returned rows is displayed. What if we want to display tens of thousands or even more items? Create a new View for each Item? Impossible !!! In fact, Android has already cached these views.

Each item in ListView is returned and displayed through getView. If there are many items, it is unreasonable to create so many objects repeatedly. Therefore, Android provides a Recycler to put items that are not being displayed into RecycleBin, and then reuse the View from RecycleBin when a new View is displayed.

Recycler generally works as follows:

Assuming that up to 11 items can be seen on the screen, When 1st items are out of the screen, the View of this item enters RecycleBin. Before the first item appears, use getView to RecycleBin) reuse this View and set the data without creating a new View.

You can take a look at the following to understand. This figure is the most classic image that explains the working principle of ListView. You can add it to your favorites and take a look at it when you don't understand it, in fact, there is a Recycler component in Android, which lists the Recycler-related things that have been optimized by Google over N, such as AbsListView. recyclerListener, ViewDebug. recyclerTraceType and so on. It's hard to understand the working principle of ListView loading data.


The principle is as follows:
  1. If you have thousands or even tens of thousands of items, only visible items have memory (Memory). optimization means Optimization in memory !) , Others are in Recycler;
  2. ListView first requests a type1 view (getView) and then requests other visible projects. ConvertView is null in getView;
  3. When item1 is out of the screen and a new project is down from the screen, ListView requests a type1 view. ConvertView is not a null value. Its value is item1. You only need to set new data and return convertView. You do not need to create a new view.

    public class MultipleItemsList extends ListActivity {              private MyCustomAdapter mAdapter;              @Override         public void onCreate(Bundle savedInstanceState) {             super.onCreate(savedInstanceState);             mAdapter = new MyCustomAdapter();             for (int i = 0; i < 50; i++) {                 mAdapter.addItem("item " + i);             }             setListAdapter(mAdapter);         }              private class MyCustomAdapter extends BaseAdapter {                  private ArrayList mData = new ArrayList();             private LayoutInflater mInflater;                  public MyCustomAdapter() {                 mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);             }                  public void addItem(final String item) {                 mData.add(item);                 notifyDataSetChanged();             }                  @Override             public int getCount() {                 return mData.size();             }                  @Override             public String getItem(int position) {                 return mData.get(position);             }                  @Override             public long getItemId(int position) {                 return position;             }                  @Override             public View getView(int position, View convertView, ViewGroup parent) {                 System.out.println("getView " + position + " " + convertView);                 ViewHolder holder = null;                 if (convertView == null) {                     convertView = mInflater.inflate(R.layout.item1, null);                     holder = new ViewHolder();                     holder.textView = (TextView)convertView.findViewById(R.id.text);                     convertView.setTag(holder);                 } else {                     holder = (ViewHolder)convertView.getTag();                 }                 holder.textView.setText(mData.get(position));                 return convertView;             }              }              public static class ViewHolder {             public TextView textView;         }     } 

Run the program to view the log:

 

GetView is called nine times. convertView is null for all visible items (as follows ):

 

Then scroll down the ListView until item10 appears:

 

ConvertView is still null, because there is no view in the recycler (the edge of item1 is still visible, at the top) and then the list is scrolled. Continue to scroll:

 

ConvertView is not a null value! Item1 leaves the screen and goes to Recycler. Then item11 is created (the view of item1 is reused) and then scroll down:

 


This problem is intuitively explained on the Internet:

================== Assume that up to 11 items can be viewed on the screen:

:

 

You can see that 10 items are displayed when Activity is opened.

Let's look at the Log information:

 

It can be seen that each convertView is null and is displayed by creating a new View.

When we slide down, such,

 

 

Because item0 and item10 are both half displayed, item10 is also created. However, when item11 is to be displayed, item0 is no longer on the screen, so item11 reuse the item0 instance. We can see from the following Log information:

By analyzing the Log information, we can see that the item11 object is item0, The item12 object is item1, and so on. In the future, item22 will reuse the view of item11, and so on.

In this way, by reusing convertView, you can avoid creating a View every time, saving memory and optimizing the sliding effect of ListView.



Based on the above principles, we will study the optimization of ListView:

First, remember two smaller points optimized by ListView:

1. expandableListView and ListActivity are officially provided. The ListView to be used in the list is an optimized ListView. If you can use the ListView provided by Google to meet your requirements, try to use the official one, absolutely!

2. secondly, if we talk about ListView optimization, it doesn't actually refer to other optimizations, that is, the optimization of memory. When we talk about memory (OOM), there are a lot of optimizations. Let's write them down first, if the options in our ListView are just some simple textviews, it will be easy to handle and consume a lot, but if your Item is a custom Item, for example, if your custom Item layout ViewGroup contains buttons, images, flash, CheckBox, RadioButton, and other controls that you can think, in getView, The ViewHolder mentioned at the beginning of the article is far from enough. If there is too much data and too many images are loaded, you can use BitmapFactory. if decode is so fierce, OOM will kill you. In this case, I will warn you again .......... Remind yourself:

If the custom ListView items are out of order, if the ListView cached data convertView is forcibly cleared in getView (), that is, convertView = null, if there is too much data, the most disgusting error is that the mobile phone is stuck or forced to shut down. Therefore, the actual problem cannot be solved simply by clearing the cache convertView.

The following is a note: the correct release after the image is used up...

If (! Bmp. isRecycle () {bmp. recycle () // reclaim the memory occupied by the image system. gc () // remind the system to recycle it in time}

Let's list the optimizations in the true sense:
  1. ViewHolder Tag is indispensable!
  2. If a custom Item involves images and so on, you must handle the image. The memory occupied by the image is the most disgusting in the ListView Item. There are roughly the following methods to process the image:
    2.1: Do not take a path directly to loop decodeFile (); Use Option to save the image size, do not load the image to the memory;
    2.2: The image obtained must be compressed by border
    2.3: When retrieving an image in ListView, do not take a path directly to retrieve the image. Instead, use WeakReference instead of forced reference. For example, you can use WeakReference <Context> mContextRef), SoftReference, and WeakHashMap to store image information!
    2.4: when converting images in getView, the generated intermediate variables must be released in time.
  3. Avoid using static in BaseAdapter to define global static variables, which has a great impact. static is a keyword in Java. When it is used to modify member variables, this variable belongs to this class, not the instance of this class. Therefore, static variables have a long life cycle. If you use them to reference instances that consume too much resources (for example, Context is the most common ), in this case, we should try to avoid using it ..
  4. If Context must be used to meet the requirements, use Application Context as much as possible. Because the life cycle of the Application Context is long, it will not cause memory leakage.
  5. Avoid using threads in the ListView adapter as much as possible, because the main cause of thread Memory leakage is the uncontrollable thread lifecycle.
  6. When using the custom ListView to adapt to data, use AsyncTask to enable the Thread itself. This is more dangerous than using Thread, because Thread only causes this memory leakage when the run function does not end, however, the implementation mechanism of AsyncTask is to use ThreadPoolExcutor. The Thread object generated by this class has an uncertain life cycle and cannot be controlled by the application, therefore, if AsyncTask is used as the internal class of the Activity, it is more prone to memory leakage. The solution to this problem is as follows:
    6.1: change the internal class of the thread to the static internal class.
    6.2: Use Weak references within the thread to save Context references.

The sample code is as follows:

public abstract class WeakAsyncTask<Params, Progress, Result, WeakTarget> extends             AsyncTask<Params, Progress, Result> {         protected WeakReference<WeakTarget> mTarget;            public WeakAsyncTask(WeakTarget target) {             mTarget = new WeakReference<WeakTarget>(target);         }            /** {@inheritDoc} */         @Override         protected final void onPreExecute() {             final WeakTarget target = mTarget.get();             if (target != null) {                 this.onPreExecute(target);             }         }            /** {@inheritDoc} */         @Override         protected final Result doInBackground(Params... params) {             final WeakTarget target = mTarget.get();             if (target != null) {                 return this.doInBackground(target, params);             } else {                 return null;             }         }            /** {@inheritDoc} */         @Override         protected final void onPostExecute(Result result) {             final WeakTarget target = mTarget.get();             if (target != null) {                 this.onPostExecute(target, result);             }         }            protected void onPreExecute(WeakTarget target) {             // No default action         }            protected abstract Result doInBackground(WeakTarget target, Params... params);            protected void onPostExecute(WeakTarget target, Result result) {             // No default action         } }

Reference:

Http://android.amberfog.com /? P = 296

Http://haking.iteye.com/blog/1147404

Http://www.cnblogs.com/itstudent/p/3729117.html (classic type)



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.