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

Source: Internet
Author: User

I. Descriptive narrative of the problem

Android applications often involve loading a large number of images from the network, to increase load speed and efficiency, and to reduce network traffic using level two caching and asynchronous loading mechanisms. The so-called level two cache is obtained from the memory first, then from the file, and then the network. The memory cache (level one) is essentially a map collection that stores the URL and bitmap information of the picture in a key-value-pair manner. Management is relatively complex because memory caches cause heap memory leaks. Third-party components can be used, for experienced can write their own components, and the file cache is relatively simple, usually self-encapsulation.

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 such as the following:

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;};        };        /** * Take picture from cache * @param ID * @return Assume that the cache has, and that 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), code such as the following

 
 public class Filecache {//Cache Files folder private file Mcachedir; /** * Create cache Files folder, fake with SD card. Then use SD, assuming no system comes with cache folder * @param context * @param cachedir Picture cache folder */public Filecache (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 Component Asyncimageloader

Android uses a single-threaded model that the app executes in the UI main thread. And Android is also the real-time operating system requires timely response or a ANR error occurs. Therefore, for time-consuming operation requirements cannot clog the UI main thread, it is necessary to open a thread processing (such as image loading in this app) and put the thread in the queue, and then notify the UI main thread to make changes when the execution is complete, remove the task at the same time-this is the asynchronous task, Implementing Async in Android can be achieved through the use of Asynctask in this series or using the Thread+handler mechanism, where it is completely written in code, so that we can see more clearly the nature of the implementation of asynchronous communication, code such as the following

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 been loaded into the picture, string> mimageviews = Collec tions. Synchronizedmap (New Weakhashmap<imageview, string> ());//Save the URL that is loading the picture private List<loadphoto    task> mtaskqueue = new arraylist<loadphototask> ();    /** * defaults to a thread pool of size 5 * @param context * @param the fast 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);//build a fixed-size thread pool with a capacity of 5 (maximum number of threads executing)}/** * Load the corresponding picture by URL * @ Param URL * @return take a picture from a first-level cache and then return directly, assuming no asynchronous from the file (level two cache), assuming no more from the network side */public Bitmap LoadBitmap (ImageView image View, String URL) {//record ImageView to M firstThe AP, which indicates that the UI has performed a picture loaded into the 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) {        Assuming the task already exists, do not add the IF (istaskexisted (URL)) return again;        Loadphototask task = new Loadphototask (URL, imageView); Synchronized (mtaskqueue) {mtaskqueue.add (Task);//Add task to queue} MEXECUTORSERVICE.EXECU    Te (Task);//Submit a task to the thread pool, assuming that there is no upper limit (5), then execute otherwise blocked}/** * Infer 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);//Get Picture with network}/** * Infer if the ImageView has already loaded the picture (can be used to infer if it is necessary 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)) {//inferred ImageView has been re-            Use Removetask (this);//Assume that the task return is deleted 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 to implement the ImageView control load Picture} removetask (this);//Remove the task from the 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 the writing is complete. It is convenient to call the LoadBitmap () method in Asyncimageloader for asynchronous tasks, and the code for the Asyncimageloader component is best combined with a good look. 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 (); }    }}
Four, 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 folder Filecache fcache=new Filecache (mactivity, CacheD    IR, "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 ("header information Test ————" +position);        Vh.ivImg.setTag (Data[position]); Asynchronously loads a picture.        First cache, then level two cache, the last network to obtain the picture 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 (); }}

A small partner who wants to learn a lot about other content. You can click to view the source code and perform the test yourself.

Inquiries or technical exchanges, please increase the official QQ group:

idkey=69fd2f84c1212ecb10062430746aa802c93431c006c1d8cd8c34c5dd4f14772d "target=" _blank "> (452379712)

Jerry Education
Source:http://blog.csdn.net/jerehedu/
This article belongs to Yantai Jerry Education Technology Co., Ltd. and CSDN co-owned, welcome reprint. However, this statement must be retained without the author's permission. And in the article page obvious location to the original link, otherwise reserves the right to pursue legal responsibility.

Copyright notice: This article Bo Master original articles, blogs, without consent may not be reproduced.

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

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.