ListView performance optimization for asynchronous loading _android

Source: Internet
Author: User
Tags garbage collection static class advantage

Android ListView is one of the highest-rate controls (the GridView and ListView are brothers, all inherited Abslistview), ListView optimization is the most effective is to use viewholder to reduce the frequent view query and update, cache images to speed up decoding, reduce picture size.

On the asynchronous loading of ListView, there are many examples on the internet, the central idea is similar, but many versions or have bugs, or performance problems to be optimized, let's explain its principle to explore the mystery in app application, ListView's asynchronous loading image can bring a good user experience, but also an important indicator to consider the performance of the program. On the ListView asynchronous loading, there are many examples on the web, the central idea is similar, but many versions or have bugs, or performance problems to be optimized. In view of this, I found a relatively ideal version on the Internet and on the basis of the transformation, let me elaborate on the following principles to explore the mysteries of the secret, and the gentlemen to share the reward ...

To load the picture in asynchronous basic idea:

1. Get the picture display (memory buffer) from the memory cache first
2. Get the words from the SD card (SD card buffer)
3. If you can't get it, download the picture from the network and save it to the SD card and add the memory and display (see if you want to display it)

OK, first on the adapter code:

public class Loaderadapter extends baseadapter{private static final String TAG = "Loaderadapter"; 
Private Boolean mbusy = false; 
public void Setflagbusy (Boolean busy) {this.mbusy = busy; 
Private Imageloader Mimageloader; 
private int mcount; 
Private context Mcontext; 
Private string[] urlarrays; 
public Loaderadapter (int count, context context, String []url) {this.mcount = count; 
This.mcontext = context; 
urlarrays = URL; 
Mimageloader = new Imageloader (context); 
Public Imageloader Getimageloader () {return mimageloader; 
@Override public int GetCount () {return mcount; 
@Override public Object getitem (int position) {return position; 
@Override public long getitemid (int position) {return position; 
@Override public View getview (int position, View Convertview, ViewGroup parent) {Viewholder viewholder = null; 
if (Convertview = = null) {Convertview = Layoutinflater.from (Mcontext). Inflate (R.layout.list_item, NULL); Viewholder = new Viewholder (); 
Viewholder.mtextview = (TextView) convertview. Findviewbyid (r.id.tv_tips); 
Viewholder.mimageview = (ImageView) convertview. Findviewbyid (R.id.iv_image); 
Convertview.settag (Viewholder); 
else {Viewholder = (Viewholder) convertview.gettag (); 
} String url = ""; 
url = urlarrays[position% urlarrays.length]; 
ViewHolder.mImageView.setImageResource (R.drawable.ic_launcher); 
if (!mbusy) {mimageloader.displayimage (URL, Viewholder.mimageview, false); ViewHolder.mTextView.setText ("--" + position +)--idle | | 
Touch_scroll "); 
else {mimageloader.displayimage (URL, Viewholder.mimageview, true); 
ViewHolder.mTextView.setText ("--" + position + "--fling"); 
return convertview; 
Static class Viewholder {TextView mtextview; 
ImageView Mimageview;  } 
}

The key code is the Imageloader DisplayImage method, and then look at the Imageloader implementation

public class Imageloader {private MemoryCache memorycache = new MemoryCache (); 
Private Abstractfilecache Filecache; Private Map<imageview, string> imageviews = collections. Synchronizedmap (New Weakhashmap<imageview, String 
> ()); 
Thread pool private Executorservice executorservice; 
Public Imageloader {filecache = new Filecache (context); 
Executorservice = Executors.newfixedthreadpool (5); }//The most important method is public void displayimage (String url, ImageView imageview, Boolean Isloadonlyfromcache) {imageviews.put (IMA 
Geview, URL); 
First look for Bitmap Bitmap = memorycache.get (URL) from the memory cache; 
if (bitmap!= null) imageview.setimagebitmap (bitmap); 
else if (!isloadonlyfromcache) {//If not, open the new line Chengga the picture queuephoto (URL, imageview); 
} private void Queuephoto (String url, ImageView imageview) {phototoload p = new Phototoload (URL, imageview); 
Executorservice.submit (New Photosloader (p)); 
Private Bitmap getbitmap (String URL) {File f = filecache.getfile (URL); First from the file slowSave to find whether there is Bitmap B = null; 
if (f!= null && f.exists ()) {b = DecodeFile (f); 
} if (b!= null) {return B; 
//finally download the picture try {Bitmap Bitmap = null from the specified URL; 
URL imageUrl = new URL (URL); 
HttpURLConnection conn = (httpurlconnection) imageUrl. OpenConnection (); 
Conn.setconnecttimeout (30000); 
Conn.setreadtimeout (30000); 
Conn.setinstancefollowredirects (TRUE); 
InputStream is = Conn.getinputstream (); 
OutputStream OS = new FileOutputStream (f); 
CopyStream (is, OS); 
Os.close (); 
Bitmap = DecodeFile (f); 
return bitmap; 
catch (Exception ex) {LOG.E ("", "Getbitmap catch exception...\nmessage =" + ex.getmessage ()); 
return null; }//decode this picture and scaling to reduce memory consumption, the virtual machine's cache size for each picture is limited private Bitmap decodefile (File f) {try {//decode image size B 
Itmapfactory.options o = new Bitmapfactory.options (); 
O.injustdecodebounds = true; 
Bitmapfactory.decodestream (new FileInputStream (f), NULL, O); Find the correct scale value. 
It should is the power of 2. Final int Required_SIZE = 100; 
int width_tmp = o.outwidth, height_tmp = o.outheight; 
int scale = 1; 
while (true) {if (Width_tmp/2 < required_size | | | HEIGHT_TMP/2 < required_size) break; 
Width_tmp/= 2; 
Height_tmp/= 2; 
Scale *= 2; 
}//decode with insamplesize bitmapfactory.options O2 = new Bitmapfactory.options (); 
O2.insamplesize = scale; 
Return Bitmapfactory.decodestream (New FileInputStream (f), NULL, O2); 
catch (FileNotFoundException e) {} return null; 
}//Task for the queue private class Phototoload {public String URL; 
Public ImageView ImageView; 
Public Phototoload (String u, imageview i) {url = u; 
ImageView = i; 
} class Photosloader implements Runnable {Phototoload phototoload; 
Photosloader (Phototoload phototoload) {this.phototoload = Phototoload; 
@Override public void Run () {if (imageviewreused (phototoload)) return; 
Bitmap bmp = Getbitmap (Phototoload.url); 
Memorycache.put (Phototoload.url, BMP); 
if (imageviewreused (phototoload)) return;Bitmapdisplayer bd = new Bitmapdisplayer (BMP, Phototoload); 
The updated operation is placed in the UI thread activity A = (activity) photoToLoad.imageView.getContext (); 
A.runonuithread (BD); }/** * Prevent picture dislocation * * @param phototoload * @return/Boolean imageviewreused (Phototoload phototoload) {String ta 
g = Imageviews.get (Phototoload.imageview); 
if (tag = = NULL | |!tag.equals (PHOTOTOLOAD.URL)) return true; 
return false; 
///To update interface class Bitmapdisplayer implements Runnable {Bitmap Bitmap in UI thread; 
Phototoload Phototoload; 
Public Bitmapdisplayer (Bitmap B, Phototoload p) {Bitmap = b; 
Phototoload = p; 
public void Run () {if (imageviewreused (phototoload)) return; 
if (bitmap!= null) photoToLoad.imageView.setImageBitmap (bitmap); 
} public void ClearCache () {memorycache.clear (); 
Filecache.clear (); 
public static void CopyStream (InputStream is, OutputStream OS) {final int buffer_size = 1024; 
try {byte[] bytes = new Byte[buffer_size]; for (;;) {int count = is.read (bytes, 0, BuffeR_size); 
if (count = = 1) break; 
Os.write (bytes, 0, count); 
} catch (Exception ex) {LOG.E ("", "CopyStream catch Exception ..."); } 
} 
}

First load from memory, no open thread from the SD card or the network to obtain, here note from the SD card to get the picture is placed in the child thread, otherwise the speed skating screen will not be fluent, this is optimized. At the same time, in the adapter has a busy variable, indicating whether the ListView is in the sliding state, if it is sliding state only from the memory to get the picture, there is no need to open the thread to the external storage or network to get pictures, which is optimized two. Threads in the Imageloader use a thread pool, which avoids the frequent creation and destruction of too many threads, and the fact that some children's shoes are always new to execute this is very undesirable, a good point of the use of the Asynctask class, the internal is also used in the thread pool. When you get a picture from the network, first save it to the SD card, and then load it into memory, the advantage is that you can do a compression when loading into memory to reduce the memory of the picture, which is optimized by three.

And the nature of the problem of image dislocation stems from our listview using a cache Convertview, assuming a scene, a ListView screen display nine item, then when pulling out the tenth item, the fact that the item is repeated use of the first item, That is, when the first item downloads a picture from the network and eventually displays it, the item is no longer in the current display area, and the result is that it will be displayed on the tenth item, which leads to the problem of image dislocation. So the solution is that visible is displayed, not visible, not displayed. In the Imageloader, there is a Imageviews map object, which is used to save the current display area image corresponding to the set of URLs, before the display to determine the processing.

Below again the memory buffer mechanism, this example uses is the LRU algorithm, first looks at the memorycache realization

public class MemoryCache {private static final String TAG = "MemoryCache"; When put into cache it is a synchronous operation//Linkedhashmap the last parameter of the constructor method True means that the elements in this map will be ranked by the number of recent usage, that is, LRU//The advantage is that if you want to replace the elements in the cache, The least recently used element is first traversed to improve efficiency. Private Map<string, bitmap> cache = collections. Synchronizedmap (New linkedhashmap< 
String, Bitmap> (1.5f, true)); The byte occupied by the picture in the cache, initial 0, which will pass this variable to strictly control the heap memory occupied by the cache private long size = 0;//Current allocated size//cache can only occupy maximum heap memory private long Lim it = 1000000;//max memory in bytes public memorycache ()//use 25% of available heap size setlimit (runtime.getruntim 
E (). MaxMemory ()/10); 
} public void Setlimit (long new_limit) {limit = New_limit; LOG.I (TAG, "memorycache'll 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, if more than will first replace the least recently used picture cache */private void Checksize () {log.i (TAG, "cache size=" + size + "length 
= "+ cache.size ()); 
if (Size > Limit) {//First traverse the least recently used element 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 (); /** * Image Memory * * <a href= ' http://www.eoeandroid.com/home.php?mod=space&uid=2768922\ ' target= ' _blank\ ' ' 
gt; @Param </A> Bitmap * * @return/Long getsizeinbytes (bitmap bitmap) {if (bitmap = null) return 0; 
return Bitmap.getrowbytes () * Bitmap.getheight (); } 
}

First limit memory picture buffer heap memory size, each time there is a picture to the cache overtime to determine whether to exceed the limit size, more than the use of the minimum to remove the picture and remove it, of course, if this is not used here, for soft reference is also feasible, Both purposes are to maximize the use of existing in memory of the image cache, to avoid duplication of garbage to increase the GC burden, oom overflow is often due to a large amount of memory instantaneous and garbage collection caused by the delay. But the difference is that the image cache in the Linkedhashmap is not retrieved before it is removed, and the image cache in SoftReference is collected by GC at any time without any other references saved. So in the use of Linkedhashmap this LRU algorithm cache is more conducive to the effective hit of the picture, of course, with the use of the words better, that is, removed from the Linkedhashmap cache into the SoftReference, which is the memory of the level two cache, Interested children's shoes extraordinary try.

The above mentioned is for ListView asynchronous loading performance optimization of all the introduction, hope to be helpful to everyone.

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.