Android uses level two cache, asynchronous load bulk load picture complete case _android

Source: Internet
Author: User
Tags int size

I. Description of the problem

Android applications often involve loading a large number of images from the network, in order to increase the speed and efficiency of loading, reduce network traffic will adopt two-level caching and asynchronous loading mechanism, the so-called two-level cache is obtained from memory, and then from the file to obtain, the last access to the network. The memory cache (level) is essentially a map collection that stores the URL and bitmap information for a picture in a key-value way, because the memory cache can cause heap memory leaks, management is relatively complex, and third-party components are available for experienced, programmable components, The file cache is simpler and usually encapsulates itself. The following is a case to see how to achieve the optimization of network picture loading.

Second, the case introduction

Picture of a list of case news

Third, the main core components

Let's take a look at the components that are written for the first-level cache (memory), level two cache (disk files)

1, MemoryCache

Store pictures in memory (first-level cache), using 1 map to cache picture code as follows:

public class MemoryCache {//MAX cache number private static final int max_cache_capacity = 30; Using map soft reference Bitmap object to ensure that the memory space will not be garbage collected private hashmap<string, softreference<bitmap>> Mcachemap = n EW linkedhashmap<string, softreference<bitmap>> () {private static final long serialversionuid = 1L; A cache quantity exceeding the specified size (return true) clears the protected Boolean removeeldestentry that was first placed in the cache (map.entry<string,softreference<bitmap>& Gt
  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.pu
  T (ID, new softreference<bitmap> (Bitmap)); /** * Clears all cache/public void clear () {Try {for (Map.entry<string,softreference<bitmap>>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 as follows

public class Filecache { 
  //cache file directory 
  private file Mcachedir;
  /**
   * Create cache file directory, if you have SD card, then use SD, if not then use the system's own cache directory
   * @param context
   * @param cachedir image cache of the first level directory
* * 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 cached storage path built into the system
   if (!mcachedir.exists ()) mcachedir.mkdirs ();
  } Public
  file getFile (String URL) {
    file f=null;
    try {
//URL is edited to resolve the 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 () {//Purge cached files
    file[] files = mcachedir.listfiles ();
    for (File f:files) f.delete ();
}


3. Write Asynchronous Load Components Asyncimageloader

Android is a single-threaded model where applications run in the main UI thread, and Android is a real-time operating system requiring timely response or ANR errors, so the UI main thread cannot be blocked for time-consuming operation requirements. You need to turn on a threading process (such as a picture in this application to load) and put the thread into the queue, and then 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 asynchronous in Android can be achieved through the use of the asynctask or the thread+handler mechanism used in this series, which is done entirely through code, so that we can see the essence of the implementation of asynchronous communication more clearly, the code is as follows

public class asyncimageloader{Private memorycache mmemorycache;//Memory cache private Filecache mfilecache;//file cache private Executorservice mexecutorservice;//thread pool//record already loaded picture of ImageView private Map<imageview, string> mimageviews =
Collections. Synchronizedmap (New Weakhashmap<imageview, string> ());
  Save the URL that is loading the picture private list<loadphototask> mtaskqueue = new arraylist<loadphototask> ();  /** * Defaults to a 5-size thread pool * @param context * @param memorycache cache * @param filecache file cache/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)}/** * The corresponding picture is loaded according to the URL * @para M URL * @return The first cache to take a picture is directly returned, if not asynchronously from the file (level two cache), if no longer from the network to obtain/public Bitmap LoadBitmap (ImageView ImageView, S Tring URL) {//ImageView to the map, indicating that the UI has been executed by the picture loaded MimagevieWs.put (ImageView, URL); Bitmap Bitmap = mmemorycache.get (URL);//First get picture if (Bitmap = = null) {Enquequeloadphoto (URL, ImageView) from a level cache;/Two
  Level caching and Network access} return bitmap; /** * Add picture download queue * @param url/private void Enquequeloadphoto (String url, ImageView imageview) {//If task
    already exists, the IF (istaskexisted (URL)) return is not added;
    Loadphototask task = new Loadphototask (URL, imageview); Synchronized (mtaskqueue) {mtaskqueue.add (Task);//Add a task to the queue Mexecutorservice.execute (Task), or to the thread pool Hand task, if not reached the upper limit (5), then run otherwise blocked}/** * Determine if the task is already present in the download queue * @param URL * @return/private Boolean Istaskexiste
    d (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 = mfilecache.getf Ile (URL);//Get cached picture path Bitmap B = Imageutil.decodefile (f);//Get File Bitmap information if (b!= null)/NOT NULL representation obtained cached file return
    b Return Imageutil.loadbitmapfromweb (URL, f);//Network Get Picture}/** * To determine if the ImageView has been loaded (can be used to determine whether the need to load pictures) * @param im  Ageview * @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 (Task);
    } 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 (i)mageviewreused (ImageView, url)) {//Determine if ImageView has been reused removetask (this);//If it has been reused, delete the task return; Bitmap bmp = Getbitmapbyurl (URL);//Get Picture Mmemorycache.put (URL, BMP) from cache file or network side;//put picture into first level cache if (!image viewreused (ImageView, url)) {//If ImageView picture is displayed in UI thread bitmapdisplayer BD = new Bitmapdisplayer (bmp, ImageView, ur            L);
      Activity A = (activity) imageview.getcontext (); A.runonuithread (BD)//In the UI thread invokes the BD component's Run method, implementing to load the picture for the ImageView control Removetask (this);//Remove task from queue public Stri
    Ng GetUrl () {return URL;
    }/** * * * The Run method that executes the component in the UI thread */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);
    }/** * Free resources/public void Destroy () {mmemorycache.clear ();
    Mmemorycache = null;
    Mimageviews.clear ();
    Mimageviews = null;
    Mtaskqueue.clear ();
    Mtaskqueue = null;
    Mexecutorservice.shutdown ();
  Mexecutorservice = null;

 }
}

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

4, Tool class Imageutil

public class Imageutil {/** * Gets a picture from the network and caches it in the specified file * @param url picture URL * @param file cache * @return * * p
    Ublic 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 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 (); The public static Bitmap DecodeFile (IOException e) {}}}} (File f) {Try {return 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. Testing and Application
Sequence diagram between components:

1, the preparation of 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.jb51.net/UserFiles/x_Image/x_20150606083511_0.jpg",
"http:// News.jb51.net/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;//Asynchronous component public Listviewadapter (activity mactivity, string[] d) {this.mactivity=
    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, Cachedir, "
  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]);
    Load the picture asynchronously, first from a cache, then two level cache, the last network to get 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 ();

 }
}

Small partners who want to know more, can click on the source and run the test themselves.

Related Article

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.