There are also a lot of articles on this aspect on the Internet. The basic idea is to solve this problem through thread + cache. Some optimizations are proposed below:
1. Use a thread pool
2. Memory Cache + File Cache
3. In the memory cache, softreference is often used on the network to prevent heap overflow. The strict limit here is that only 1/4 of the maximum JVM memory can be used.
4. Scale the downloaded image proportionally to reduce memory consumption.
The specific code is described in. Put the memory cache class code memorycache. Java:
Public class memorycache {Private Static final string tag = "memorycache "; // when the data is cached, It is a synchronization operation. // The final parameter true of the linkedhashmap constructor method indicates that the elements in the map will be sorted by the number of recent uses from less to more, that is, the advantage of LRU // is that if you want to replace the elements in the cache, first traverse the least recently used elements to replace them to improve the efficiency of 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 will be used to strictly control the heap memory occupied by the cache private long size = 0; // current allocated size // The cache can only Maximum heap memory occupied private long limit = 1000000; // Max memory in bytespublic memorycache () {// use 25% of available heap sizesetlimit (runtime. getruntime (). maxmemory ()/4);} 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 exceeds the limit, 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 recently used minimum 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 ();}/*** memory occupied by the image ** @ Param bitmap * @ return */long getsizeinbytes (Bitmap bitmap) {If (Bitmap = NULL) return 0; return bitmap. getrowbytes () * bitmap. getheight ();}}
You can also use softreference. The code is much simpler, but I recommend the above method.
public class MemoryCache {private Map<String, SoftReference<Bitmap>> cache = Collections.synchronizedMap(new HashMap<String, SoftReference<Bitmap>>());public Bitmap get(String id) {if (!cache.containsKey(id))return null;SoftReference<Bitmap> ref = cache.get(id);return ref.get();}public void put(String id, Bitmap bitmap) {cache.put(id, new SoftReference<Bitmap>(bitmap));}public void clear() {cache.clear();}}
The following is the file cache code filecache. Java:
Public class filecache {private file cachedir; Public filecache (context) {// if there is an SD card, create a lazylist directory on the SD card to store cached images. // If (Android. OS. environment. getexternalstoragestate (). equals (Android. OS. environment. media_mounted) cachedir = new file (Android. OS. environment. getexternalstoragedirectory (), "lazylist"); elsecachedir = context. getcachedir (); If (! Cachedir. exists () cachedir. mkdirs ();} public file GetFile (string URL) {// use the URL hashcode as the cached file name string filename = string. valueof (URL. hashcode (); // another possible solution // string filename = urlencoder. encode (URL); file F = new file (cachedir, filename); Return F;} public void clear () {file [] files = cachedir. listfiles (); If (Files = NULL) return; For (file F: Files) F. delete ();}}
Finally, the most important class for loading images is imageloader. Java:
Public class imageloader {memorycache = new memorycache (); filecache; private Map <imageview, string> imageviews = collections. synchronizedmap (New weakhashmap <imageview, string> (); // thread pool executorservice; Public imageloader (context) {filecache = new filecache (context); executorservice = executors. newfixedthreadpool (5);} // The default image when you enter the listview, which can be replaced with your own default image final in T stub_id = R. drawable. stub; // main method public void displayimage (string URL, imageview) {imageviews. put (imageview, URL); // first query Bitmap bitmap = memorycache from the memory cache. get (URL); If (Bitmap! = NULL) imageview. setimagebitmap (Bitmap); else {// if not, enable the new thread to load the image queuephoto (URL, imageview); imageview. setimageresource (stub_id) ;}} private void queuephoto (string URL, imageview) {phototoload P = new phototoload (URL, imageview); executorservice. submit (New photosloader (p);} private bitmap getbitmap (string URL) {file F = filecache. getFile (URL); // first query the File Cache for bitmap B = decodefile (f); If (B! = NULL) return B; // finally download the image from the specified URL try {Bitmap bitmap = NULL; Url imageurl = new URL (URL); httpurlconnection conn = (httpurlconnection) imageurl. openconnection (); Conn. setconnecttimeout (30000); Conn. setreadtimeouts (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) {ex. printstacktrace (); return NULL ;}// decode this image and scales proportionally to reduce memory consumption, the cache size of each image is also limited by the Virtual Machine private bitmap decodefile (file F) {try {// decode image sizebitmapfactory. options o = new bitmapfactory. options (); O. injustdecodebounds = true; bitmapfactory. decodestream (New fileinputstream (F), null, O); // find the correct scale value. it shoshould be the power of 2. final int required_size = 70; in T 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 insamplesizebitmapfactory. options O2 = new bitmapfactory. options (); o2.insamplesize = scale; return bitmapfactory. decodestream (New fileinputstream (F), null, O2);} catch (filenotfoundexception E) {} return NULL;} // task for the queueprivate class phototoload {Public String URL; Public imageview; Public phototoload (string U, imageview I) {url = u; imageview = I ;}} class photosloader implements runnable {phototoload; photosloader (phototoload) {This. phototoload = phototoload;} @ overridepublic void run () {If (imageviewreused (phototoload) return; bitmap BMP = getbit Map (phototoload. URL); memorycache. put (phototoload. URL, BMP); If (imageviewreused (phototoload) return; bitmapdisplayer BD = new bitmapdisplayer (BMP, phototoload); // update the operation in the UI thread activity A = (activity) phototoload. imageview. getcontext ();. runonuithread (BD) ;}}/*** prevents image misplacement ** @ Param phototoload * @ return */Boolean imageviewreused (phototoload) {string tag = imageviews. get (phototoload. imagevie W); If (TAG = NULL |! Tag. equals (phototoload. URL) return true; return false;} // used to update the interface class bitmapdisplayer implements runnable {Bitmap bitmap; phototoload; Public bitmapdisplayer (Bitmap B, phototoload P) in the UI thread) {bitmap = B; phototoload = P;} public void run () {If (imageviewreused (phototoload) return; If (Bitmap! = NULL) phototoload. imageview. setimagebitmap (Bitmap); elsephototoload. imageview. setimageresource (stub_id) ;}} public void receivache () {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 ){}}}
The main process is to first look up from the memory cache. If no thread is opened and no search from the File Cache is found, search from the specified URL and process bitmap, finally, update the UI using the following method.
a.runOnUiThread(...);
Basic usage in your program:
ImageLoader imageLoader=new ImageLoader(context);...imageLoader.DisplayImage(url, imageView);
For example, if you put it in the getview () method of the adapter of your listview, it also applies to the gridview.
OK. First come here.