Moment For Technology

ListView optimization

Posted on Aug. 8, 2022, 6:49 p.m. by Renee Nicholas
Category: The code of life Tag: Big data


Proficient in ListView optimization, acquisition of network pictures asynchronous loading, batch loading, paging display, image caching and other optimization methods

** First take a look at how ListView works (see As shown in figure: For each item, the Adapter is asked to "return a view" (getView). When the ListView starts drawing, the adapter calls getCount (). According to its return value, the ListView returns the length of the view. Call getView () to draw each item of the ListView line by line. If your getCount () returns 0, none of the rows are displayed. If your getCount () returns 1, only one row is displayed. Return several to display several lines. What if we have thousands of items to display? Create a new View for each Item? No way!! Android already caches these recyclable views. This is a screenshot that explains how ListView works. If you don't know how to recycle it, we can recycle it. Here are some examples of Recycler that Have been optimized by Google: AbsListView. RecyclerListener, ViewDebug. RecyclerTraceType, etc., to know friends checked himself, it is easy to understand, below is the working principle of ListView loading data (schematic diagram to see not clear after click to enlarge) :

! [How ListView loads data]( 60723184023200)

1. If you have several thousand or more items, only the visible items are in memory. 2. ListView requests a type1 view first and then requests other visible items to Recycler. ConvertView is null in getView. 3. When Item1 rolls off the screen and a new item comes up from the lower end of the screen, the ListView requests a Type1 view. ConvertView is not null at this point, it's item1. You just set the new data and return the convertView, you don't have to create a new view

ConvertView, reduce the number of findViewById ConvertView Android system itself for us to consider the ListView optimization problem, in the copy Adapter class, the two more important methods are getCount() and getView(). The getView() method is called as many times as there are bars on the screen; So if you do not optimize the View.inflate(... .). XML files are parsed and displayed on the interface, which is very resource-intensive: old content is destroyed as new content is created, so old content can be reused. Optimization: in the getView() method, the system provides us with a history cache object convertView for reuse of views. When the first screen is displayed, each item will create a new view object, which can be reused. If you had to create a view every time you displayed it, it would be very memory consuming; So, to save memory, we can reuse convertView when it is not null. The ViewHolder findViewById() method is a costly operation because it finds the specified layout file and continuously parses each node: Parse the query layer by layer from the topmost node, find it and return it layer by layer, if not found on the left, then parse the right and query it until the location is found (figure). 》》》》 features: When an XML file is parsed, its child's ID does not change as long as it is created. With this feature, the child ID can be stored in a specified collection, and the corresponding element in the collection can be directly fetched each time. Optimization: Reduce the number of times layout files are converted to View objects when creating view objects. The ViewHolder class is not required to be static. The ViewHolder class is not required to be static. If there are not many items, the ViewHolder class is required to be static. So when you initialize it, you only load it once, so it's a little bit more optimized but if you have too many items, you don't want to use it. Because static is a keyword in Java, when you use it to modify a member variable, the variable belongs to that class, not an instance of that class. Static variables have a long lifetime and should be avoided if they are used to refer to resource-consuming instances (Context is the most common instance). Class ViewHolder{// define the corresponding control in item} Add child view to holder: When you create a new listView, create a new ViewHolder, find all the children, and save the child's reference to the view and set the reference to the view through view.settag (holder) and set the child view into the holder, In order to reduce the number of future queries ④ in the reuse of listView entries, through view.getTag(), the view object into the holder, that is, into the corresponding reference, convenient in the next use of time to store in the collection. Get the reference via view.getTag(holder) (strong)

Need: ListView has ten thousand data, how to display; If you load 100,000 pieces of data into the memory, it consumes a lot of memory. Solution: Optimize the query data: Obtain several pieces of data and display them on the interface for batch processing. -  optimize user experience and pagination. Data is usually obtained from the database. To achieve batch (paging) loading of data, there is a corresponding method to obtain data in batches in the corresponding DAO, such as findPartDatas (). FindPartDatas () : findPartDatas (); findPartDatas () : findPartDatas (); SetOnScrollListener (new OnScrollListener {... }) inside the listener, there are two methods: onScrollStateChanged and onScroll called while listView is being rolled SCROLL_STATE_TOUCH_SCROLL: // FlGIN: scroll_state_scroll: // FlGIN: SCROLL_STATE_IDLE: Load data in batches and only care about the rest state. Care about the last visible item. If the last visible item is the last one in the data adapter (set), more data can be loaded. At each load, count the number of scrolls. When the number of scrolls is greater than or equal to the total number, the user can be reminded that there is no more data.

The ListView interface display is controlled by getCount and getView these two methods: getCount: return how many items getView: return the contents of each position item display. Optimizations for items containing multiple types: Since the ListView has only one Adapter entry, we can define a total Adapter entry that holds various types of Adapter. Take the process management function in the security guard as an example. 1. Define two (or more) collections, each containing a different type of content. FillData (userAppinfos, systemAppinfos, userAppinfos, systemAppinfos, userAppinfos, systemAppinfos, userAppinfos, systemAppinfos); Count all items to display, including listView and textView getView() : 4. Judgment of data type It needs to be noted that when multiplexing views, convertView type judgment is needed, because there are various types of views, in view scrolling display, for different types of view can not be multiplexed. All need to be judged

1, the way of processing pictures: if the custom Item involves pictures and so on, be sure to severely process pictures, pictures account for the memory of the ListView Item is the most disgusting, there are roughly the following methods of processing pictures: ①, don't take path directly to the loop decodeFile(); Use Option to save the size of the picture, do not load the picture into memory to ②, get the picture must go through the boundary compression ③, when taking the picture in ListView, do not directly take a path to take the picture, but with WeakReference (use WeakReference instead of strong reference. For example, you can use WeakReference mContextRef, SoftReference, WeakHashMap, etc., to store picture information, which is picture information, not picture oh! 4, in getView to do the image conversion, the generated intermediate variables must be released in time 2, asynchronous loading picture basic idea: 1), first from the memory cache to obtain the picture display (memory buffer) 2), if can not obtain from the SD card (SD card buffer) 3), if can not obtain from the network download the picture and save to the SD card at the same time add memory and display (depending on the situation to see whether to display)

Principle: Optimization 1: load from memory first, if there is no open thread from the SD card or network to obtain pictures from the SD card is in the sub-thread, otherwise it will not smooth fast slide screen. In the adapter, there is a busy variable that indicates whether the ListView is sliding or not. If the listView is sliding, it only retrieves images from memory. If the listView is sliding, there is no need to open the thread to retrieve images from memory or network. The ImageLoader thread uses a thread pool to avoid multiple threads being created and destroyed. Some AsyncTask classes use a new thread at a time. This is not desirable. When you get pictures from the network, you save them to the SD card first, and then load them into memory. The advantage of this is that you can compress them to reduce the memory occupied by the pictures. Tips: There may be a problem with the image jumping (dislocation) : The essence of the image mismatch problem comes from the fact that our ListView uses the cache convertView. Suppose a scenario where a ListView displays nine items on one screen, then when pulling out the tenth item, it actually reuses the first item. That is to say, when the first item downloads the picture from the network and finally displays it, in fact, the item is no longer in the current display area, and the result of display at this time may output the image on the tenth item, which leads to the problem of image dislocation. So the solution is to show it if you see it, and not show it if you don't see it. 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.

3, memory buffer mechanism: first limit the heap memory size of memory image buffer, each time there is an image added to the cache to determine whether the size exceeds the limit, if more than the least used image from the image and remove it. Of course, if this method is not adopted here, it is also feasible to use soft reference, both of which are to maximize the use of the image cache already existing in memory, and avoid repeated garbage generation and increase the BURDEN of GC. OOM overflow is usually caused by a large memory increase and garbage collection is not timely. The difference is that a LinkedHashMap image cache is not retrieved by GC until it is removed, whereas a SoftReference image cache is retrieved at any time if no other reference is saved. Therefore, LRU algorithm such as LinkedHashMap is more conducive to image matching. Of course, the effect is better if the two algorithms are used together, that is, the cache removed from LinkedHashMap is put into SoftReference, which is the second-level cache of memory.

In this example, the LRU algorithm is used. Let's take a look at the MemoryCache implementation

public class MemoryCache { private static final String TAG = "MemoryCache"; // The last parameter of the LinkedHashMap constructor true means that the elements in the map will be arranged in order of the least recent use, i.e. LRU // The advantage of this is that if you want to replace the elements in the cache, Private MapString, Bitmap cache = collections. synchronizedMap(new LinkedHashMapString, Bitmap  (10, 1.5 f, true)); Private long size = 0; private long size = 0; private long size = 0; // Allocated memory size private long limit = 1000000; // Allocated memory size 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 controls heap memory, Private void checkSize() {log. I (TAG, "cache size=" + size + "length=" + cache.size()); private void checkSize() {log. I (TAG, "cache size=" + size +" length=" + cache.size()); If (size  limit) {// IteratorEntryString, Bitmap iter = cache.entryset ().iterator(); while (iter.hasNext()) { EntryString, Bitmap entry =; size -= getSizeInBytes(entry.getValue()); iter.remove(); if (size = limit) break; } Log.i(TAG, "Clean cache. New size " + cache.size()); } } public void clear() { cache.clear(); } / picture memory * * * *  a href = "\"\ "" target =" \ "_blank \" " @ Param  / a  bitmap * @return */ long getSizeInBytes(Bitmap bitmap) { if (bitmap == null) return 0; return bitmap.getRowBytes() * bitmap.getHeight(); }}Copy the code

Avoid using static in BaseAdapter to define global static variables: static is a Java keyword. When you use it to modify a member variable, that variable belongs to the class, not an instance of that class. Static variables have a long lifetime and should be avoided if they are used to refer to resource-consuming instances (Context is the most common instance). 2. Use getApplicationContext as much as possible: If Context must be used in order to satisfy your requirements: Use the ListView adaptor as an example. The ListView adaptor uses the ListView adaptor as an example. The ListView adaptor uses the ListView adaptor as an example. The main reason for memory leaks is that the thread life cycle is out of control. This is more dangerous than using a Thread, because threads only leak when the run function does not end. However, the internal implementation mechanism of AsyncTask uses ThreadPoolExcutor. The life cycle of Thread objects generated by this class is uncertain and beyond the control of the application. Therefore, if AsyncTask is used as an internal class of an Activity, More prone to memory leaks. The solution is as follows: ①, change the thread inner class, static inner class. Use weak references inside the thread to save Context references

About (Moment For Technology) is a global community with thousands techies from across the global hang out!Passionate technologists, be it gadget freaks, tech enthusiasts, coders, technopreneurs, or CIOs, you would find them all here.