Android Performance Optimization-Listview optimization, android-listview

Source: Internet
Author: User

Android Performance Optimization-Listview optimization, android-listview

ListViewWorking principle

First of all to understand the working principle of ListView (see http://mobile.51cto.com/abased-410889.htm ),

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. 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, when you don't understand it, let's take a look at it and get a better understanding. In fact, there is a Recycler component in Android that 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 by yourself. (The figure below shows the figure clearly ):

 

1. If you have thousands or even tens of thousands of items, only visible items have memory (memory, optimization means Optimization in memory !!!) In the Recycler.

2. ListView first requests a type1 view (getView) and then requests other visible projects. ConvertView is null in getView.

3. When item1 gets out of the screen and a new project comes from the low end of the screen, ListView then 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.

I. ReuseConvertView, ReduceFindViewByIdNumber of times

1. Optimization 1: Reuse convertView

The Android system itself considers the ListView optimization problem for us. In the secondary Adapter class, the more important two methods are getCount () and getView (). The number of display entries on the interface, the number of getView () methods will be called. Therefore, if you do not optimize each call, View will be used each time. inflate (....) The xml file must be parsed and displayed on the interface. This consumes a lot of resources. Because new content is generated, old content will be destroyed, the old content can be reused.

Optimization:

In the getView () method, the system provides a historical cache object convertView for reusing views. When the first screen is displayed, a new view object is created for each item, these views can be reused. If you need to create a view each time, it is very memory-consuming. To save memory, when convertView is not null, reuse it

2. Optimization 2: cache reference of item entries-ViewHolder

FindViewById () is a performance-consuming operation, because this method needs to locate the specified layout file and continuously parse each node: perform a layer-by-layer resolution query on the top node, and then return a layer-by-layer query. If it is not found on the left side, it then parses the right side and performs the corresponding query, until the location () is found (). Therefore, you can optimize findViewById. Note the following:

"Features: When an xml file is parsed, its child id will not change as long as it is created. Based on this feature, the child id can be saved to the specified set, and each time the corresponding elements in the set can be directly retrieved.

Optimization:

When creating a view object, reduce the number of times that the layout file is converted into a view object. That is, when creating a view object, locate all the children and store the reference of the children.

① Define the class ViewHolder referenced by the storage control

The ViewHolder class does not need to be defined as static. It depends on the actual situation. If there are not many items, you can use it. In this way, it is loaded only once during initialization, some optimizations are available.

However, if there are too many items, we recommend that you do not use them. Because static is a keyword in Java, when it is used to modify the member variable, the variable belongs to the class, rather than the instance of the 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, try to avoid using it.

Class ViewHolder {

// Define the corresponding controls in item

}

② Create a custom class: ViewHolder holder = null;

③ Add the sub-view to holder:

When creating a new listView, create a new ViewHolder, locate all the children, and store the reference of the child.

Set Reference to view using view. setTag (holder)

Use holder to set the child view to this holder to reduce the number of future queries

④ When reusing the items in the listView, convert the view object to holder through view. getTag (), that is, convert the view object to the corresponding reference, so that it can be saved to the set in the next use.

Obtain reference through view. getTag (holder) (strong conversion required)

II,ListViewBatch and paging loading of data in:

Requirements:How to display 10 thousand pieces of data in ListView; if 100,000 pieces of data are loaded into memory, memory consumption is very high.

Solution:

Optimize the queried data: first obtain several data entries and display them on the interface.

Batch Processing --- à optimizes User Experience

Paging processing --- à optimized memory space

Note:

Generally, data is obtained from the database. To load data in batches (by PAGE), you need to obtain data in batches (by PAGE) in the corresponding DAO, such as findPartDatas ()

1. Prepare data:

How to add batch data loading in dao: findPartDatas ()

When adapting to data, load the first batch of data first. When loading the second batch, set the listener to detect when to load the second batch.

2. Set the ListView rolling listener: setOnScrollListener (new OnScrollListener {....})

① There are two methods in the listener: onScrollStateChanged and onScroll)

② There are three states in the method of changing the rolling status:

The status when the finger is pressed and moved: SCROLL_STATE_TOUCH_SCROLL: // touch the slider.

Inertial rolling (flgin) status): SCROLL_STATE_FLING: // gliding

Static status: SCROLL_STATE_IDLE: // static

3. process different statuses:

Load data in batches and focus only on the static state: focus on the last visible entry. If the last visible entry is the last one in the data adapter (SET), more data can be loaded. During each loading, the number of scrolls is calculated. When the number of scrolls is greater than or equal to the total number, you can be prompted to have no more data.

Iii. ComplexityListView(To be further summarized)

Note:

The listView interface is controlled by the getCount and getView methods.

GetCount: the number of returned entries.

GetView: returns the content displayed for each position entry.

Provide ideas:

Optimization for items containing multiple types: Because ListView only has one Adapter portal, you can define a total Adapter portal to store various types of adapters.

Take the process management function in security guard as an example. Effect

1. Define two (or more) Sets

Each collection is saved with different types of content (here: User Program (userAppinfos) and system program set (systemAppinfos ))

2. initialize two sets in the initialization data (fill data ).

For example, this is initialized in the fillData method.

3. In the data adapter, rewrite the corresponding method

GetCount (): calculates the number of entries to be displayed, including listView and textView.

GetView (): if processing of entries displayed in different locations

4. Data Type Determination

When reusing views, You need to determine the type of convertView because it contains different types of views, different types of views cannot be reused. All views must be judged.

IV,ListViewPicture optimization: For details, seeOOMOptimization of Abnormal images

1. Image Processing Methods:

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:

① Do not take the path directly to loop decodeFile (); Use Option to save the image size, do not load the image to the memory

②. The image must be compressed through the border.

③ 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 mContextRef), SoftReference, and WeakHashMap to store image information!

④ When converting images in getView, the generated intermediate variables must be released in time

2Basic Idea of asynchronous image loading:

1) First, get the image display from the memory cache (memory buffer)

2) If not, get it from the SD card (SD card buffer)

3) If none of them can be obtained, download the image from the network, save it to the SD card, add the memory, and display it (depending on the situation, whether to display it)

Principle:

Optimization 1: load the image from the memory first, and enable the thread to retrieve the image from the SD card or the network. Note that the image obtained from the SD card is executed in the sub-thread, otherwise, the screen will not be smooth enough.

Optimization 2: At the same time, there is a busy variable in the adapter, indicating whether the listview is in the sliding state. If it is in the sliding state, only the image is obtained from the memory, if no, you do not need to enable the thread to store images or obtain images from the network.

Optimization 3: the threads in ImageLoader use the thread pool to avoid frequent creation and destruction of multithreading. Some shoes are always executed by a new thread at a time, which is very undesirable, A better AsyncTask class is used internally. When you get an image from the network, you first save it to the SD card and then load it To the memory. The advantage of this is that you can perform compression processing when loading the image to the memory, to reduce the memory occupied by images.

Tips: The image may be in disorder:

The essence of the image dislocation problem is that our listview uses the cached convertView. In this scenario, if a listview displays nine items on one screen, when the tenth item is pulled out, in fact, this item uses the first item repeatedly. That is to say, when the first item downloads the image from the network and finally needs to be displayed, the item is no longer in the current display area, at this time, the result of the display may be output on the tenth item, which leads to the picture dislocation problem. Therefore, the solution is to display the Visible data, but not the Visible data. In ImageLoader, there is a map object of imageViews, which is used to save the url set corresponding to the image in the current display area. You can determine and process it before display.

 

3. memory buffer mechanism:

First, limit the heap memory size of the memory image buffer. Each time an image is added to the cache, determine whether the size exceeds the limit. If the size exceeds the limit, the minimum used image will be taken out and removed.

Of course, if this method is not used here, it is also feasible to use soft references. Both of them aim to maximize the use of the image cache that already exists in the memory, so as to avoid repeated garbage production and increase the GC burden; OOM overflow is often caused by the instantaneous increase in memory and the garbage collection is not timely. However, the difference between the two lies in that the image cache in the LinkedHashMap will not be recycled by GC before it is removed, and the image cache in SoftReference will be recycled by GC at any time when there are no other references. Therefore, the LRU algorithm cache, such as LinkedHashMap, is more conducive to the effective hit of images. Of course, the cache removed from LinkedHashMap is better if the two are used together, that is, the cache removed from LinkedHashMap is placed in SoftReference, this is the second-level cache of the memory.

 

This example uses the LRU algorithm. First, let's look at the implementation of MemoryCache.

Public class MemoryCache {

Private static final String TAG = "MemoryCache ";

// It is a synchronization operation when it is put into the cache.

// The final parameter true of the LinkedHashMap constructor indicates that the elements in the map will be sorted by the number of recent calls, that is, LRU.

// The advantage is that if you want to replace the elements in the cache, traverse the least recently used elements to replace them to improve efficiency.

Private Map <String, Bitmap> cache = Collections

. SynchronizedMap (new LinkedHashMap <String, Bitmap> (10, 1.5f, true ));

// The Bytes occupied by the image in the cache. The initial value is 0. This variable strictly controls the heap memory occupied by the cache.

Private long size = 0; // current allocated size

// Maximum heap memory that the cache can only occupy

Private long limit = 1000000; // max memory in bytes

Public MemoryCache (){

// Use 25% of available heap size

SetLimit (Runtime. getRuntime (). maxMemory ()/10 );

}

Public void setLimit (long new_limit ){

Limit = new_limit;

Log. I (TAG, "MemoryCache will use up to" + limit/1024./1024. + "MB ");

}

Public Bitmap get (String id ){

Try {

If (! Cache. containsKey (id ))

Return null;

Return cache. get (id );

} Catch (NullPointerException ex ){

Return null;

}

}

Public void put (String id, Bitmap bitmap ){

Try {

If (cache. containsKey (id ))

Size-= getSizeInBytes (cache. get (id ));

Cache. put (id, bitmap );

Size + = getSizeInBytes (bitmap );

CheckSize ();

} Catch (Throwable th ){

Th. printStackTrace ();

}

}

/**

* Strictly control the heap memory. If the heap memory is exceeded, replace the image cache that is least recently used.

*

*/

Private void checkSize (){

Log. I (TAG, "cache size =" + size + "length =" + cache. size ());

If (size> limit ){

// First traverse the least recently used elements

Iterator <Entry <String, Bitmap> iter = cache. entrySet (). iterator ();

While (iter. hasNext ()){

Entry <String, Bitmap> entry = iter. next ();

Size-= getSizeInBytes (entry. getValue ());

Iter. remove ();

If (size <= limit)

Break;

}

Log. I (TAG, "Clean cache. New size" + cache. size ());

}

}

Public void clear (){

Cache. clear ();

}

 

/**

* Memory occupied by images

* <A href = "\" http://www.eoeandroid.com/home.php? Mod = space & uid = 2768922 \ "" target = "\" _ blank \ ""> @ Param </a> bitmap

* @ Return

*/

Long getSizeInBytes (Bitmap bitmap ){

If (bitmap = null)

Return 0;

Return bitmap. getRowBytes () * bitmap. getHeight ();

}

}

 

V,ListViewOther optimizations:

1. Avoid using static in BaseAdapter to define global static variables as much as possible:

Static is a keyword in Java. When it is used to modify a member variable, the variable belongs to the class, rather than the instance of the 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, try to avoid using it.

2. Use getApplicationContext whenever possible:

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.

3. Avoid using threads in the ListView adapter as much as possible:

The main cause of thread Memory leakage is the uncontrollable thread lifecycle. 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 is as follows:

① Change the internal class of the thread to the static internal class.

② Use weak references within the thread to save Context references

 

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.