Online on this aspect of the article also a lot, the basic idea is thread + cache to solve. Some optimizations are presented below:
1, the use of thread pool
2, Memory cache + file cache
3, the memory cache in many of the internet is to use softreference to prevent heap overflow, here strictly limit only the maximum JVM memory 1/4
4, to download the picture to scale proportionally to reduce memory consumption
Specific code inside the description. Put the code Memorycache.java of the memory cache class first:
Copy Code code as follows:
<span style= "font-size:18px" ><strong>public class MemoryCache {
private static final String TAG = "MemoryCache";
A synchronization operation when putting in the cache
The last argument of the Linkedhashmap constructor true means that the elements in this map will be sorted by the number of recent uses, that is, the LRU
The advantage is that if you want to replace the elements in the cache, you can replace them with the least recently used element 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 control the heap memory occupied by the cache strictly
Private long size = 0;//Current Allocated size
Maximum heap memory that can be consumed by caching
Private long limit = 1000000;//max memory in bytes
Public MemoryCache () {
Use 25% of available heap size
Setlimit (Runtime.getruntime (). MaxMemory ()/4);
}
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 ();
}
}
/**
* Strict control of heap memory, if more than will first replace the least recently used image cache
*
*/
private void Checksize () {
LOG.I (TAG, "cache size=" + size + "length=" + cache.size ());
if (Size > limit) {
First iterate through 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 ();
}
/**
* The memory occupied by the picture
*
* @param bitmap
* @return
*/
Long Getsizeinbytes (Bitmap Bitmap) {
if (bitmap = null)
return 0;
return Bitmap.getrowbytes () * Bitmap.getheight ();
}
}</strong></span>
You can also use SoftReference, the code is much simpler, but I recommend the above method.
Copy Code code as follows:
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 code Filecache.java for the file cache class:
Copy Code code as follows:
public class Filecache {
Private File Cachedir;
Public Filecache {
If there is an SD card in the SD card to build a lazylist directory to store cached pictures
No SD card is placed in the system's cache directory
if (Android.os.Environment.getExternalStorageState (). Equals (
Android.os.Environment.MEDIA_MOUNTED))
Cachedir = new File (
Android.os.Environment.getExternalStorageDirectory (),
"Lazylist");
Else
Cachedir = Context.getcachedir ();
if (!cachedir.exists ())
Cachedir.mkdirs ();
}
Public File getFile (String URL) {
Hashcode the URL as the cached filename
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 ();
}
}
The last and most important class to load the picture, Imageloader.java:
Copy Code code as follows:
public class Imageloader {
MemoryCache memorycache = new MemoryCache ();
Filecache Filecache;
Private Map<imageview, string> imageviews = Collections
. Synchronizedmap (New Weakhashmap<imageview, string> ());
Thread pool
Executorservice Executorservice;
Public Imageloader {
Filecache = new Filecache (context);
Executorservice = Executors.newfixedthreadpool (5);
}
When you enter the ListView default picture, you can replace it with your own default picture
Final int stub_id = r.drawable.stub;
The most important way
public void displayimage (String url, ImageView imageview) {
Imageviews.put (ImageView, URL);
Find from the memory cache first
Bitmap Bitmap = memorycache.get (URL);
if (bitmap!= null)
Imageview.setimagebitmap (bitmap);
else {
If not, turn on the new line Chengga to download the picture
Queuephoto (URL, imageview);
Imageview.setimageresource (stub_id);
}
}
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);
To find out from the file cache first whether there are
Bitmap B = DecodeFile (f);
if (b!= null)
return b;
Finally download the picture from the specified URL
try {
Bitmap Bitmap = null;
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) {
Ex.printstacktrace ();
return null;
}
}
Decode this picture and scaling it proportionally to reduce memory consumption, the virtual machine has a limited cache size for each picture.
Private Bitmap DecodeFile (File f) {
try {
Decode Image size
Bitmapfactory.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 = 70;
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 action 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 tag = Imageviews.get (Phototoload.imageview);
if (tag = null | |!tag.equals (PHOTOTOLOAD.URL))
return true;
return false;
}
Used to update the interface in the UI thread
Class Bitmapdisplayer implements Runnable {
Bitmap Bitmap;
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);
Else
PhotoToLoad.imageView.setImageResource (stub_id);
}
}
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) {
}
}
}
The main process is to look up from the memory cache, if there is no more thread, from the file cache lookup is not found from the specified URL, and bitmap processing, and finally through the following method to update the UI.
Copy Code code as follows:
Basic usage in your program:
Copy Code code as follows:
<span style= "font-size:18px" ><strong>imageloader imageloader=new imageloader (context);
...
Imageloader.displayimage (URL, imageview);</strong></span>
For example, the GetView () method that you put in your ListView adapter, of course, applies to the GridView.