Android Batch Image loading classic series--using two-level cache, asynchronous loading network pictures

Source: Internet
Author: User

First, the problem description

Android applications often involve loading a large number of images from the network, in order to improve loading speed and efficiency, reduce network traffic will adopt the two-level cache and asynchronous loading mechanism, so-called two-level cache is by first get from memory, then get from the file, and finally access the network. The memory cache (level one) is essentially a map collection that stores the URL and bitmap information of the image in Key-value pairs, because the memory cache can cause heap memory leaks, management is relatively complex, can use third-party components, for experienced can write their own components, The file cache is relatively simple and usually encapsulates itself. The following is a case study of how to achieve network image loading optimization.

Second, Case introduction

List picture of case News

Third, the main core components

Let's take a look at the components written to implement the first level cache (memory), level two cache (disk file)

1, MemoryCache

The image is stored in memory (first-level cache), using 1 maps to cache the image code as follows:

public class MemoryCache {//maximum number of caches private static final int max_cache_capacity = 30;             Using the map soft reference Bitmap object, ensure that the memory space is not garbage collected private hashmap<string, softreference<bitmap>> Mcachemap = New linkedhashmap<string, softreference<bitmap>> () {private static final long serialversion UID = 1l;//When the number of caches exceeds the specified size (returns TRUE) clears the protected Boolean removeeldestentry that was first placed in the cache (Map.entry<string,softrefere    Nce<bitmap>> eldest) {return size () > max_cache_capacity;};        };        /** * Remove picture from cache * @param ID * @return If the cache has and the picture is not released, return the picture, otherwise return null */public BITMAP get (String ID) {        if (!mcachemap.containskey (ID)) return null;        Softreference<bitmap> ref = Mcachemap.get (ID);    return Ref.get ();        /** * Add picture to cache * @param ID * @param bitmap */public void put (String ID, bitmap bitmap) { Mcachemap.put (ID, new softreference<bitmap> (BITMAP)); }/** * Clears all caches */public void Clear () {try {for (MAP.ENTRY&LT;STRING,SOFTREFERENCE&LT;BITMAP&G            T;>entry:mcachemap.entryset ()) {softreference<bitmap> sr = Entry.getvalue ();                if (null! = SR) {Bitmap BMP = Sr.get ();            if (null! = BMP) Bmp.recycle ();    }} mcachemap.clear ();    } catch (Exception e) {e.printstacktrace ();} }}
2, Filecache

Cache pictures on disk (Level two cache), the code is as follows

 
 public class Filecache {//cache files directory private file Mcachedir; /** * Create the cache file directory, if there is an SD card, then use SD, if not then use the system comes with cache directory * @param context * @param cachedir picture cache of the first level directory */public Filecach E (Context context, File Cachedir, String dir) {if (Android.os.Environment.getExternalStorageState (). Equals, (      Android.os.Environment.MEDIA_MOUNTED)) Mcachedir = new File (Cachedir, dir);    else Mcachedir = Context.getcachedir ();//How to obtain the system's built-in cache storage path if (!mcachedir.exists ()) mcachedir.mkdirs ();        } Public file GetFile (String url) {file f=null;            try {//Edit URL to solve Chinese path problem String filename = urlencoder.encode (URL, "Utf-8");        f = new File (mcachedir, filename);        } catch (Unsupportedencodingexception e) {e.printstacktrace ();    } return F;        public void Clear () {///Clear Cache file file[] files = mcachedir.listfiles (); for (File f:files) F.delete ();}} 
3. Write Asynchronous Load Components Asyncimageloader

The single-threaded model in Android is running in the main thread of the UI, and Android is a real-time operating system that requires a timely response or a ANR error, so the time-consuming operation requires that the UI main thread not be blocked. You need to turn on a threading (such as a picture load in this app) and put the thread in the queue, notify the UI main thread to make changes when the run is complete, and remove the task-this is the asynchronous task, The implementation of async in Android can be achieved through the use of Asynctask in this series or using the Thread+handler mechanism, where the code is completely written, so that we can see more clearly the nature of the implementation of asynchronous communication, the code is as follows

public class asyncimageloader{Private memorycache mmemorycache;//Memory cache private Filecache mfilecache;//file cache privat e executorservice mexecutorservice;//thread pool//record ImageView private map<imageview that have loaded the picture, string> mimageviews = Collec tions. Synchronizedmap (New Weakhashmap<imageview, string> ());//Save the URL where the picture is being loaded private List<loadphoto    task> mtaskqueue = new arraylist<loadphototask> ();    /** * Default to a thread pool of size 5 * @param context * @param the cache used by MemoryCache * @param the file cache used by the Filecache * * Public Asyncimageloader (context context, MemoryCache MemoryCache, Filecache filecache) {Mmemorycache = MemoryCache        ;        Mfilecache = Filecache; Mexecutorservice = Executors.newfixedthreadpool (5);//Establish a fixed-size thread pool with a capacity of 5 (maximum number of running threads)}/** * Load the corresponding picture according to the URL * @ Param URL * @return take a picture from a first-level cache is returned directly, if not the asynchronous from the file (level two cache), if no more from the network side to obtain */public Bitmap LoadBitmap (ImageView image View, String URL) {//record ImageView to M firstThe AP, which indicates that the UI has performed a picture loaded with Mimageviews.put (ImageView, URL); Bitmap Bitmap = mmemorycache.get (URL);//Get picture if (Bitmap = = null) From first-level cache {Enquequeloadphoto (URL, Imagevie    W);//Get the} return bitmap from the level two cache and the network;        /** * Add picture download queue * @param URL */private void Enquequeloadphoto (String url, ImageView ImageView) {        If the task already exists, do not re-add the IF (istaskexisted (URL)) return;        Loadphototask task = new Loadphototask (URL, imageView); Synchronized (mtaskqueue) {mtaskqueue.add (Task);//Add task to queue} MEXECUTORSERVICE.EXECU    Te (Task),///to commit the task to the thread pool, or to run otherwise blocked if the upper limit (5) is not reached}/** * determine if the task already exists in the download queue * @param URL * @return */        Private Boolean istaskexisted (String URL) {if (url = = null) return false;            Synchronized (mtaskqueue) {int size = Mtaskqueue.size (); for (int i=0; i<size; i++) {loadphototask task = MTAsKqueue.get (i);            if (Task! = null && task.geturl (). Equals (URL)) return true;    }} return false; /** * Get picture from cache file or network side * @param URL */private Bitmap getbitmapbyurl (String URL) {File f = m Filecache.getfile (URL);//Gets the cached picture path Bitmap B = Imageutil.decodefile (f);//Gets the Bitmap information of the file if (b! = null)//NOT NULL to get        The cached file return B; Return Imageutil.loadbitmapfromweb (URL, f);//with the network to obtain the picture}/** * Determine if the ImageView has already loaded the picture (can be used to determine whether to load the picture) * @ param imageView * @param url * @return */Private Boolean imageviewreused (ImageView imageView, String URL)        {String tag = Mimageviews.get (ImageView);        if (tag = = NULL | |!tag.equals (URL)) return true;    return false; } private void Removetask (Loadphototask Task) {synchronized (mtaskqueue) {Mtaskqueue.remove (TAS        k); }} class Loadphototask ImplemEnts Runnable {private String URL;            Private ImageView ImageView;            Loadphototask (String URL, ImageView ImageView) {this.url = URL;        This.imageview = ImageView; } @Override public void Run () {if (imageviewreused (ImageView, url)) {//To determine if ImageView has been re-            Use Removetask (this);//Delete the task return if it has been reused;            } Bitmap bmp = Getbitmapbyurl (URL);//Get Picture Mmemorycache.put (URL, BMP) from cache file or network side;//Put picture in first level cache if (!imageviewreused (ImageView, url)) {//If the ImageView picture is not added, the picture is displayed in the UI thread bitmapdisplayer BD = new Bitmapdisplaye                        R (BMP, ImageView, URL);            Activity A = (activity) imageview.getcontext ();        A.runonuithread (BD);//Invoke the Run method of the BD component on the UI thread, implement load picture for ImageView control} removetask (this);//Remove task from queue}        Public String GetUrl () {return URL;   }}/** * * is executed by the UI thread in the Run method of the component  */class Bitmapdisplayer implements Runnable {private Bitmap Bitmap;        Private ImageView ImageView;        Private String URL;            Public Bitmapdisplayer (Bitmap B, ImageView ImageView, String url) {Bitmap = b;            This.imageview = ImageView;        This.url = URL;            public void Run () {if (imageviewreused (ImageView, URL)) return;        if (bitmap! = null) imageview.setimagebitmap (bitmap);        }}/** * Release resource */public void Destroy () {mmemorycache.clear ();        Mmemorycache = null;        Mimageviews.clear ();        Mimageviews = null;        Mtaskqueue.clear ();        Mtaskqueue = null;        Mexecutorservice.shutdown ();    Mexecutorservice = null; }}

After writing, it is very convenient to call the LoadBitmap () method in Asyncimageloader for the execution of an asynchronous task, and the code for the Asyncimageloader component is best combined with annotations to understand This will be a deep understanding of the asynchronous communication between Android threads.

4, Tool class Imageutil
public class Imageutil {/** * Gets the picture from the network and caches it in the specified file * @param url image URL * @param file cache * @return *        /public static Bitmap loadbitmapfromweb (String url, file file) {HttpURLConnection conn = null;        InputStream is = null;        OutputStream OS = null;            try {Bitmap Bitmap = null;            URL imageUrl = new URL (URL);            conn = (httpurlconnection) imageurl.openconnection ();            Conn.setconnecttimeout (30000);            Conn.setreadtimeout (30000);            Conn.setinstancefollowredirects (TRUE);            is = Conn.getinputstream ();            OS = new FileOutputStream (file);            CopyStream (is, OS);//cache the picture to disk bitmap = DecodeFile (file);        return bitmap;            } catch (Exception ex) {ex.printstacktrace ();        return null;                } finally {try {if (OS! = null) os.close ();                if (is! = null) is.close (); IF (conn! = NULL) Conn.disconnect (); } catch (IOException e) {}}} public static Bitmap DecodeFile (File f) {try {Retu        RN Bitmapfactory.decodestream (new FileInputStream (f), NULL, NULL);    } catch (Exception e) {} return null;        } private 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) {ex.printstacktrace (); }    }}
Iv. Test Application

Timing diagram between components:

1, write Mainactivity
public class Mainactivity extends Activity {     ListView list;    Listviewadapter adapter;    @Override public    void OnCreate (Bundle savedinstancestate) {        super.oncreate (savedinstancestate);        Setcontentview (r.layout.main);        List= (ListView) Findviewbyid (r.id.list);        Adapter=new Listviewadapter (this, mstrings);        List.setadapter (adapter);    }    public void OnDestroy () {        list.setadapter (null);        Super.ondestroy ();        Adapter.destroy ();    }  Private string[] mstrings={"http://news.21-sun.com/UserFiles/x_Image/x_20150606083511_0.jpg", "http// News.21-sun.com/userfiles/x_image/x_20150606082847_0.jpg ",.....};}
2. Write the adapter
public class Listviewadapter extends Baseadapter {private Activity mactivity;    Private string[] data;    private static Layoutinflater Inflater=null; Private Asyncimageloader imageloader;//Async component Public Listviewadapter (Activity mactivity, string[] d) {This.mactiv        ity=mactivity;        Data=d;        Inflater = (layoutinflater) mactivity.getsystemservice (Context.layout_inflater_service); MemoryCache mcache=new memorycache ();//Memory cache File SDcard = Android.os.Environment.getExternalStorageDirectory ();// Get SD card File Cachedir = new file (sdcard, "Jereh_cache");//cache root Filecache fcache=new filecache (mactivity, Cachedi    R, "News_img");//File Cache Imageloader = new Asyncimageloader (mactivity, Mcache,fcache);    } public int GetCount () {return data.length;    } public Object GetItem (int position) {return position;    } public long Getitemid (int position) {return position; public view GetView (int position, view Convertview, VIewgroup parent) {Viewholder vh=null;            if (convertview==null) {Convertview = inflater.inflate (R.layout.item, NULL);            Vh=new Viewholder ();            Vh.tvtitle= (TextView) Convertview.findviewbyid (R.id.text);            Vh.ivimg= (ImageView) Convertview.findviewbyid (r.id.image);                Convertview.settag (VH);        }else{vh= (Viewholder) Convertview.gettag ();        } vh.tvTitle.setText ("Title Information Test ————" +position);        Vh.ivImg.setTag (Data[position]);        Loading images asynchronously, first from a cache, then two cache, the last network to obtain pictures Bitmap bmp = Imageloader.loadbitmap (vh.ivimg, data[position]);        if (BMP = = null) {Vh.ivImg.setImageResource (r.drawable.default_big);        } else {Vh.ivImg.setImageBitmap (BMP);    } return Convertview;        } private class viewholder{TextView tvtitle;    ImageView ivimg;    } public void Destroy () {Imageloader.destroy (); }}

To learn more about the small partners, you can click to view the source code , run the test yourself.

Inquiries or technical exchanges, please join the official QQ Group: (452379712)

Jerry Education
Source:http://blog.csdn.net/jerehedu/
This article is the copyright of Yantai Jerry Education Technology Co., Ltd. and CSDN Common, welcome reprint, but without the author's consent must retain this paragraph statement, and in the article page obvious location to the original link, otherwise reserves the right to pursue legal responsibility.

Android Batch Image loading classic series--using two-level cache, asynchronous loading network pictures

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.