Design a simple Android image loading frame _android

Source: Internet
Author: User
Tags commit stub

The current Android development has so far excellent picture loading framework too many, such as: Volley, picasso,imageloader,glide and so on. But as a program ape, understand the principle of implementation is still very important, only understand to better use. So, today I simply design a network load picture frame. The main is familiar with the image of the network loading mechanism.

In general, an excellent picture loading framework (Imageloader) should have the following features:

Picture compression

Memory Cache

Disk caching

Synchronized loading of pictures

Asynchronous loading of pictures

Network Pull

Then we will introduce from the above several aspects:

1. Image compression (effective reduction of the probability of occurrence of oom)

Image compression features I have done in the efficient loading of bitmap has been introduced here is not much to say directly on the code. Here is a direct abstraction of a class to complete the image compression function.

public class Imageresizer {private static final String TAG = "Imageresizer";
  Public Imageresizer () {super (); TODO auto-generated Constructor stub} public Bitmap Decodesampledbitmapfromresource (resources res, int resid,
  T reqwidth, int reqheight) {final bitmapfactory.options Options = new Bitmapfactory.options ();
  Options.injustdecodebounds = true;

  Bitmapfactory.decoderesource (res, resid, options);

  Options.insamplesize = calculateinsamplesize (options, Reqwidth, reqheight);
  Options.injustdecodebounds = false;
 Return Bitmapfactory.decoderesource (res, resid, options); Public Bitmap Decodesampledbitmapfrombitmapfiledescriptor (filedescriptor fd, int reqwidth,int reqheight) {final B
  Itmapfactory.options Options = new Bitmapfactory.options ();

  Options.injustdecodebounds = true;

  Bitmapfactory.decodefiledescriptor (FD, NULL, options);

  Options.insamplesize = calculateinsamplesize (options, Reqwidth, reqheight); Options.injustdecodebounds = false;
 Return Bitmapfactory.decodefiledescriptor (FD, NULL, options);

 }
 public int calculateinsamplesize (bitmapfactory.options Options,
   int reqwidth, int reqheight) {

  final int width = Options.outwidth;
  Final int height = options.outheight;

  int insamplesize = 1;
  if (Height > reqheight | | | width > reqwidth) {
   final int halfheight = HEIGHT/2;
   Final int halfwidth = WIDTH/2;
   while ((halfheight/insamplesize) > Reqheight
     && (halfwidth/insamplesize) > Halfwidth) {
    Insamp Lesize *= 2;
   }
  Return insamplesize

 }

}

2. Memory Cache and Disk cache

The cache directly selects LruCache and Disklrucache to complete the memory cache and disk cache work.

Initialize it first:

Private lrucache<string, bitmap> Mmemorycache;
Private Disklrucache Mdisklrucache;

Public Imageloader {
  mcontext = Context.getapplicationcontext ();
  The allocated memory cache is 1/8 of the current process, and the disk cache capacity is 50M
  int maxmemory = (int) (Runtime.getruntime (). MaxMemory () * 1024);
  int cacheSize = MAXMEMORY/8;
  Mmemorycache = new lrucache<string, bitmap> (cacheSize) {

   @Override
   protected int sizeOf (String key, Bitmap value) {return
    value.getrowbytes () * value.getheight ()/1024;
   }

  };

  File Diskcachedir = Getdiskchahedir (Mcontext, "Bitmap");
  if (!diskcachedir.exists ()) {
   diskcachedir.mkdirs ();
  }
  if (Getusablespace (Diskcachedir) > Disk_cache_size) {
   try {
    Mdisklrucache = Disklrucache.open ( Diskcachedir, 1, 1,
      disk_cache_size);
    Misdisklrucachecreated = true;
   } catch (IOException e) {
    e.printstacktrace ();}}}
 

Once created, the next step is to provide a way to view additions and features. First look at the memory cache.

private void Addbitmaptomemorycache (String key, Bitmap Bitmap) {
  if (getbitmapfrommemcache (key) = null) {
   Mmemorycache.put (key, bitmap);
  }

 Private Bitmap Getbitmapfrommemcache (String key) {return
  mmemorycache.get (key);
 }

Memory caching is relatively simple, and disk caching is much more complex. Disk caching (Lrudiskcache) does not provide a way to implement the method directly, but to add and read the file system through editor and snapshot.

First look at Editor, which provides a commit and abort method to commit and undo write operations to the file system.

Writes the downloaded picture to the file system, implementing the disk cache
 private Bitmap loadbitmapfromhttp (String url, int reqwidth, int reqheight)
   throws IOException {
  if (looper.mylooper () = = Looper.getmainlooper ()) {
   throw new RuntimeException ("Can not visit Network from UI Thread. ");
  if (Mdisklrucache = null) return
   null;
  String key = Hashkeyformurl (URL);
  Disklrucache.editor Editor = Mdisklrucache.edit (key);
  if (editor!= null) {
   OutputStream outputstream = Editor
     . Newoutputstream (disk_cache_index);
   if (Downloadurltostream (URL, outputstream)) {
    editor.commit ();
   } else {
    editor.abort ();
   }

  }
  Mdisklrucache.flush ();
  Return Loadbitmapfordiskcache (URL, reqwidth, reqheight);
 }

Snapshot, it can get the disk cache object corresponding to the FileInputStream, but fileinputstream not easy to compress, so through the filedescriptor to load the compressed image, Finally, the loaded bitmap is added to the memory cache.

Public Bitmap loadbitmapfordiskcache (String url, int reqwidth, int reqheight)
   throws IOException {
  if ( Looper.mylooper () = = Looper.getmainlooper ()) {
   LOG.W (TAG, "load bitmap from UI Thread, it's not recommended");
  if (Mdisklrucache = null) return
   null;
  Bitmap Bitmap = null;
  String key = Hashkeyformurl (URL);
  Disklrucache.snapshot Snapshot = Mdisklrucache.get (key);
  if (snapshot!= null) {
   FileInputStream FileInputStream = (fileinputstream) snapshot
     . getInputStream (disk_ Cache_index);
   FileDescriptor filedescriptor = Fileinputstream.getfd ();
   Bitmap = Mimageresizer.decodesampledbitmapfrombitmapfiledescriptor (
     filedescriptor, Reqwidth, reqHeight);
   if (bitmap!= null) {
    Addbitmaptomemorycache (key, bitmap);
   }
  }
  return bitmap;
 }

3. Synchronous loading

Methods that are loaded synchronously need to be called externally in child threads.

Synchronous load Public
 Bitmap LoadBitmap (String uri, int reqwidth, int reqheight) {Bitmap Bitmap
  = Loadbitmpafrommemcache (URI);
  if (bitmap!= null) {return
   bitmap;
  }
  try {
   bitmap = Loadbitmapfordiskcache (URI, Reqwidth, reqheight);
   if (bitmap!= null) {return
    bitmap;
   }
   Bitmap = Loadbitmapfromhttp (URI, Reqwidth, reqheight);

  } catch (IOException e) {
   e.printstacktrace ();
  }
  if (bitmap = = null &&!misdisklrucachecreated) {
   bitmap = Downloadbitmapfromurl (URI);
  }
  return bitmap;
 }

You can see from the method that the work process follows the following steps:

First try to read the picture from the memory cache, and then try to read the picture from the disk cache before pulling it from the network. This method can no longer be executed in the main thread, and the detection of the execution environment is implemented in Loadbitmapfromhttp.

if (looper.mylooper () = = Looper.getmainlooper ()) {
   throw new RuntimeException ("Can not visit network the from UI Thread." );
  }

4. Asynchronous loading

Asynchronously loads the public
 void Bindbitmap (Final String URI, final ImageView imageview, final
   int reqwidth, final int reqheight ) {

  Imageview.settag (Tag_key_uri, URI);
  Bitmap Bitmap = Loadbitmpafrommemcache (URI);
  if (bitmap!= null) {
   imageview.setimagebitmap (bitmap);
   return;
  }
  Runnable loadbitmaptask = new Runnable () {

   @Override public
   void Run () {
    Bitmap Bitmap = LoadBitmap (URI, re Qwidth, reqheight);
    if (bitmap!= null) {
     Loaderresult result = new Loaderresult (ImageView, Uri,
       bitmap);
     Mmainhandler.obtainmessage (Message_post_result, result)
       sendtotarget ();

    }}
   }
  ;
  Thread_pool_executor.execute (Loadbitmaptask);
 }

From the Bindbitmap implementation, the Bindbitmap method will try to read the picture from the memory cache, if the reading succeeds directly return the result, otherwise it will call the LoadBitmap method in the thread pool, when the picture is successfully loaded and then the picture, The address of the picture and the imageview that need to be bound are encapsulated into a Loaderresult object, and then sent a message to the main thread via Mmainhandler, so that you can set the picture for ImageView in the main thread.

Let's take a look at the thread pool and handler used in this method, first bindbitmap the thread pool Thread_pool_executor implementation.

private static final int cpu_count = Runtime.getruntime ()
   . Availableprocessors ();
private static final int core_pool_size = Cpu_count + 1;
private static final int maximum_pool_size = Cpu_count * 2 + 1;
Private static final long keep_alive = 10L;


private static final Threadfactory sthreadfactory = new Threadfactory () {
  private final atomicinteger mcount = new Ato Micinteger ();

  @Override public
  Thread Newthread (Runnable r) {
   //TODO auto-generated method stub return
   new Thread (R, "Ima geloader# "+ mcount.getandincrement ());
  }
 };


public static final Executor thread_pool_executor = new Threadpoolexecutor (
   core_pool_size, Maximum_pool_size, Keep_alive, Timeunit.seconds,
   new linkedblockingdeque<runnable> (), sthreadfactory);


1. Reasons for using thread pooling and handler.

First, you can not use the ordinary thread to achieve, if the use of ordinary threads to load pictures, as the list of sliding may produce a large number of threads, this is not conducive to the promotion of efficiency. Handler, the main thread looper is used to construct the Handler object, which makes the imageloader can be constructed in a non main thread. In addition, in order to solve the problem of list dislocation caused by view reuse, the ImageView will check his URL before setting the picture, and if the change is not set to the picture, it will solve the problem of list dislocation.

Private Handler Mmainhandler = new Handler (Looper.getmainlooper ()) {

  @Override public
  void Handlemessage ( Message msg) {
   Loaderresult result = (Loaderresult) msg.obj;
   ImageView ImageView = Result.imageview;
   Imageview.setimagebitmap (RESULT.BITMAP);
   String uri = (string) imageview.gettag (Tag_key_uri);
   if (Uri.equals (Result.uri)) {
    imageview.setimagebitmap (result.bitmap);
   } else {
    LOG.W (TAG, "set image Bitmap,but URL has changed, ignored! ");}}

 ;

Summarize:

The problem of picture loading, especially the loading of a large number of images, has been a troubling problem for Android developers. This article only mentions the most basic one kind of solution, for the study is still good.

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

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.