Android-asynchronous image Loader

Source: Internet
Author: User

Loading images in ListView is very common. image loading must meet the following requirements:

(1) Whether the image is on the network or local, the loading should not be synchronous, but should be asynchronously loaded, such as AsyncTask.

(2) cache is generally required to avoid the speed at which images and page displays are repeatedly downloaded, for example, the most common LruCache.

(3) to improve the performance of Listview, we usually use holder to reuse the items of Listview.

The code is like this:

Public class MainActivity extends Activity {private ImageLoader imageLoader; @ Overrideprotected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); imageLoader = new ImageLoader (new ImageDownloader () {@ Overridepublic Bitmap download (String path, int width, int height) {return HttpUtil. download (path) ;}}); final ListView listview = (ListView) this. findViewById (R. id. listview); Button btn = (Button) this. findViewById (R. id. btn); btn. setOnClickListener (new View. onClickListener () {@ Overridepublic void onClick (View v) {List
 
  
DataList = getDataList (); listview. setAdapter (new ListViewAdapter (MainActivity. this, dataList) ;}}) ;}@ Overrideprotected void onDestroy () {super. onDestroy (); imageLoader. destory ();} private class ListViewAdapter extends BaseAdapter {private Context context; private List
  
   
DataList; public ListViewAdapter (Context context, List
   
    
DataList) {this. context = context; this. dataList = dataList;} @ Overridepublic int getCount () {return dataList. size () ;}@ Overridepublic Object getItem (int position) {return dataList. get (position) ;}@ Overridepublic long getItemId (int position) {return position ;}@ Overridepublic View getView (int position, View convertView, ViewGroup parent) {Holder holder = null; if (convertView = null) {holder = new Holder () ; ConvertView = new ItemView (context); holder. itemView = (ItemView) convertView; convertView. setTag (holder);} else {holder = (Holder) convertView. getTag ();} ItemView itemView = holder. itemView; ImageView itemImageView = itemView. getImageView (); ItemBean item = dataList. get (position); // first set a default image. // if this parameter is not set, when the page slides to an item being loaded, this item is the previously displayed item that has been reused. The item will first display the image of the previous item. After downloading the item, replace the image, // If the download takes a long time The user is confused about the picture! ItemImageView. setImageResource (R. drawable. ic_launcher); // download the actual image imageLoader. loadImage (item. getImagePath (), 50, 50, itemImageView); return itemView;} class Holder {ItemView itemView ;}}
   
  
 

Now the problem arises. Consider the following scenarios:

It takes a long time to download an image, for example, 10 s. Three items are displayed on each page.

When a user opens the page for the first time, item0, item1, and item2 are displayed on the first page. When item0 has not been downloaded, the user slides to the 3rd page, which should display item6, item7, and item8. The items on this page must be those on the first page of reuse. At this time, the user waits for the page to load. If item6 is item0, item7 is item1, and item8 is item2, after item0 is downloaded, item6 displays the image on item0, this is confusing! The correct image is displayed in item6 only after item6 has downloaded its own image! If the user slides continuously during the loading process, the page that the user sees is totally out of order!

The image loader in this article can avoid this problem. It was written by a colleague and feels good. I just took it and read the code:

Public class ImageLoader {private static final String TAG = "ImageLoader"; private ImageCache cache; private HashSet
 
  
CacheKeys = new HashSet
  
   
(); Private ImageDownloader downloader; // stores the relationship between filepath and ImageView. Because ImageView is reused, only this relationship is correct. // only one imageView can correspond to one filepath, a filepath corresponds to a physical file private WeakHashMap
   
    
ImageView2FileMap = new WeakHashMap
    
     
(); // A filepath may correspond to multiple imageviews, because multiple imageviews may display the same image private HashMap.
     
      
> File2ImageViewMap = new HashMap
      
        > (); // The filepath that is being read or is already in the queue. After reading the file, delete the private HashSet.
       
         FileInLoadSet = new HashSet
        
          (); Public ImageLoader (ImageDownloader downloader) {if (downloader = null) {throw new RuntimeException ("ImageDownloader can not be null");} this. cache = ImageCache. getInstance (); this. downloader = downloader ;} /*** set an image for imageView ** @ param filePath * image path * @ param width * @ param height * @ param imageView * @ return cache, set directly, return true, no asynchronous reading, read and set again, return false */public boolean loadImage (String filePath, int width, int height, ImageView imageView) {String filePathKey = getKeyForFilePath (filePath, width, height); Bitmap bmp = cache. get (filePathKey); if (bmp = null) {ImageViewReference imageViewRef = new ImageViewReference (imageView); // update the latest relationship between imageView and filepath imageView2FileMap. put (imageView, filePathKey); HashSet
         
           ImageViewSet = file2ImageViewMap. get (filePathKey); if (imageViewSet = null) {imageViewSet = new HashSet
          
            (); File2ImageViewMap. put (filePathKey, imageViewSet);} imageViewSet. add (imageViewRef); // if (fileInLoadSet. contains (filePathKey) {return false;} else {fileInLoadSet. add (filePathKey);} Holder holder = new Holder (); holder. width = width; holder. height = height; holder. filePath = filePath; holder. filePathKey = filePathKey; holder. imageViewRef = imageViewRef; new imageloadtask(cmd.exe cute (holder); return false;} else {imageView. setImageBitmap (bmp); return true;} private class ImageLoadTask extends AsyncTask
           
             {@ Overrideprotected Holder doInBackground (Holder... params) {Holder holder = params [0]; int width = holder. width; int height = holder. height; String filePath = holder. filePath; String filePathKey = holder. filePathKey; // find all imageviews corresponding to the key. if the number of imageviews is 0, int count = getCountOfImageViewForKey (filePathKey) is not downloaded. if (count <= 0) {return null;} try {Random rnd = new Random (); Thread. sleep (int) (1000 * rnd . NextDouble ();} catch (Exception e) {e. printStackTrace ();} // start reading and put it into cacheif (downloader! = Null) {// Bitmap bmp = ImageUtil. compressBitmap (filePath, width, height); Bitmap bmp = downloader. download (filePath, width, height); if (bmp! = Null) {cache. put (filePathKey, bmp); cacheKeys. add (filePath); holder. imageData = bmp ;}} return holder ;}@ Overrideprotected void onPostExecute (Holder holder) {super. onPostExecute (holder); // after reading the image, remove the key from String filePathKey = holder. filePathKey; fileInLoadSet. remove (filePathKey); Bitmap data = holder. imageData; if (data = null) {return;} ArrayList
            
              ImageViewArrayList = getImageViewListForKey (filePathKey); if (imageViewArrayList. size () = 0) {return;} // traverses the imageview list, use imageView2FileMap to find out whether the latest latestFilePathKey corresponding to the imageView is the downloaded filePathKey. // The latest latestFilePathKey must be displayed only after it is downloaded. Otherwise, the imageView has been reused, corresponding to the new keyfor (ImageView imageView: imageViewArrayList) {String latestFilePathKey = imageView2FileMap. get (imageView); if (latestFilePathKey! = Null & latestFilePathKey. equals (filePathKey) {if (imageView! = Null) {imageView. setImageBitmap (data); Log. e (TAG, "set image");/** boolean isSet; * try {* isSet = (Boolean) * imageView. getTag (); *} catch (Exception e) {* isSet = true; *} * if (isSet) {* imageView. setImageBitmap (result); * Log. e (TAG, "set image"); *} */} // The imageView2FileMap will be automatically recycled even if it is not removed. remove (imageView);} else {}} file2ImageViewMap. remove (filePathKey) ;}} class Holder {int width, height; String filePath, filePathKey; Bitmap imageData; ImageViewReference imageViewRef;} private String getKeyForFilePath (String imagePath, int width, int height) {return imagePath + "_" + width + "_" + height;}/*** destroy ImageLoader ***/public void clear () {imageView2FileMap. clear (); file2ImageViewMap. clear (); fileInLoadSet. clear (); for (String cacheKey: cacheKeys) {cache. remove (cacheKey);} cacheKeys. clear (); imageView2FileMap = null; file2ImageViewMap = null; fileInLoadSet = null; cacheKeys = null; downloader = null; cache = null;}/*** destroy ImageLoader, call ***/public void destory () {clear (); ImageCache. destroy ();} public interface ImageDownloader {public Bitmap download (String path, int width, int height );} /*** use file2ImageViewMap to obtain the list of all imageviews corresponding to filePath and delete the recycled imageView. ** @ param filePathKey * @ return */private ArrayList
             
               GetImageViewListForKey (String filePathKey) {ArrayList
              
                ImageViewArrayList = new ArrayList
               
                 (); HashSet
                
                  ImageViewReferences = file2ImageViewMap. get (filePathKey); if (imageViewReferences = null) {return null;} Iterator
                 
                   It = imageViewReferences. iterator (); while (it. hasNext () {ImageViewReference reference = it. next (); if (reference. get ()! = Null) {imageViewArrayList. add (reference. get ();} else {it. remove () ;}return imageViewArrayList ;} /*** get the number of valid imageviews corresponding to the specified filePath *** @ param filePathKey * @ return */private int getCountOfImageViewForKey (String filePathKey) {ArrayList
                  
                    ImageViewArrayList = getImageViewListForKey (filePathKey); if (imageViewArrayList = null) {return 0;} else {return imageViewArrayList. size () ;}} private static class ImageCache extends LruCache
                   
                     {Private static final int cacheSize = 10*1024*1024; private static ImageCache instance = new ImageCache (cacheSize); public static ImageCache getInstance () {return instance ;} private ImageCache (int maxSize) {super (maxSize) ;}@ Overrideprotected int sizeOf (String key, Bitmap value) {return value. getByteCount ();} public static void destroy () {if (instance = null) {return;} instance. evictAll (); instance = null;} private static class ImageViewReference extends WeakReference
                    
                      {Public ImageViewReference (ImageView r) {super (r) ;}@ Overridepublic boolean equals (Object o) {ImageViewReference other = (ImageViewReference) o; return this. get () = other. get () ;}@ Overridepublic int hashCode () {ImageView imageView = this. get (); if (imageView! = Null) {return imageView. hashCode () ;}return 0 ;}}}
                    
                   
                  
                 
                
               
              
             
            
           
          
         
        
       
      
     
    
   
  
 
Source code here: http://download.csdn.net/download/goldenfish1919/7320823

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.