Android编程之图片(异步)加载类

应某人之请,写一篇关于图片加载类。其实,网上有很多这样的类,而且比较推崇的是来自google中开源中的一篇。他写的比较好了,而且注意了内存优化,下面贴出它的图片下载类:

[java] view plaincopy
 
  1. /* 
  2.  * Copyright (C) 2010 The Android Open Source Project 
  3.  * 
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  * 
  8.  *      http://www.apache.org/licenses/LICENSE-2.0 
  9.  * 
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License. 
  15.  */  
  16.   
  17. package com.example.android.imagedownloader;  
  18.   
  19. import org.apache.http.HttpEntity;  
  20. import org.apache.http.HttpResponse;  
  21. import org.apache.http.HttpStatus;  
  22. import org.apache.http.client.HttpClient;  
  23. import org.apache.http.client.methods.HttpGet;  
  24. import org.apache.http.impl.client.DefaultHttpClient;  
  25.   
  26. import android.graphics.Bitmap;  
  27. import android.graphics.BitmapFactory;  
  28. import android.graphics.Color;  
  29. import android.graphics.drawable.ColorDrawable;  
  30. import android.graphics.drawable.Drawable;  
  31. import android.net.http.AndroidHttpClient;  
  32. import android.os.AsyncTask;  
  33. import android.os.Handler;  
  34. import android.util.Log;  
  35. import android.widget.ImageView;  
  36.   
  37. import java.io.FilterInputStream;  
  38. import java.io.IOException;  
  39. import java.io.InputStream;  
  40. import java.lang.ref.SoftReference;  
  41. import java.lang.ref.WeakReference;  
  42. import java.util.HashMap;  
  43. import java.util.LinkedHashMap;  
  44. import java.util.concurrent.ConcurrentHashMap;  
  45.   
  46. /** 
  47.  * This helper class download images from the Internet and binds those with the provided ImageView. 
  48.  * 
  49.  * <p>It requires the INTERNET permission, which should be added to your application‘s manifest 
  50.  * file.</p> 
  51.  * 
  52.  * A local cache of downloaded images is maintained internally to improve performance. 
  53.  */  
  54. public class ImageDownloader {  
  55.     private static final String LOG_TAG = "ImageDownloader";  
  56.   
  57.     public enum Mode { NO_ASYNC_TASK, NO_DOWNLOADED_DRAWABLE, CORRECT }  
  58.     private Mode mode = Mode.NO_ASYNC_TASK;  
  59.       
  60.     /** 
  61.      * Download the specified image from the Internet and binds it to the provided ImageView. The 
  62.      * binding is immediate if the image is found in the cache and will be done asynchronously 
  63.      * otherwise. A null bitmap will be associated to the ImageView if an error occurs. 
  64.      * 
  65.      * @param url The URL of the image to download. 
  66.      * @param imageView The ImageView to bind the downloaded image to. 
  67.      */  
  68.     public void download(String url, ImageView imageView) {  
  69.         resetPurgeTimer();  
  70.         Bitmap bitmap = getBitmapFromCache(url);  
  71.   
  72.         if (bitmap == null) {  
  73.             forceDownload(url, imageView);  
  74.         } else {  
  75.             cancelPotentialDownload(url, imageView);  
  76.             imageView.setImageBitmap(bitmap);  
  77.         }  
  78.     }  
  79.   
  80.     /* 
  81.      * Same as download but the image is always downloaded and the cache is not used. 
  82.      * Kept private at the moment as its interest is not clear. 
  83.        private void forceDownload(String url, ImageView view) { 
  84.           forceDownload(url, view, null); 
  85.        } 
  86.      */  
  87.   
  88.     /** 
  89.      * Same as download but the image is always downloaded and the cache is not used. 
  90.      * Kept private at the moment as its interest is not clear. 
  91.      */  
  92.     private void forceDownload(String url, ImageView imageView) {  
  93.         // State sanity: url is guaranteed to never be null in DownloadedDrawable and cache keys.  
  94.         if (url == null) {  
  95.             imageView.setImageDrawable(null);  
  96.             return;  
  97.         }  
  98.   
  99.         if (cancelPotentialDownload(url, imageView)) {  
  100.             switch (mode) {  
  101.                 case NO_ASYNC_TASK:  
  102.                     Bitmap bitmap = downloadBitmap(url);  
  103.                     addBitmapToCache(url, bitmap);  
  104.                     imageView.setImageBitmap(bitmap);  
  105.                     break;  
  106.   
  107.                 case NO_DOWNLOADED_DRAWABLE:  
  108.                     imageView.setMinimumHeight(156);  
  109.                     BitmapDownloaderTask task = new BitmapDownloaderTask(imageView);  
  110.                     task.execute(url);  
  111.                     break;  
  112.   
  113.                 case CORRECT:  
  114.                     task = new BitmapDownloaderTask(imageView);  
  115.                     DownloadedDrawable downloadedDrawable = new DownloadedDrawable(task);  
  116.                     imageView.setImageDrawable(downloadedDrawable);  
  117.                     imageView.setMinimumHeight(156);  
  118.                     task.execute(url);  
  119.                     break;  
  120.             }  
  121.         }  
  122.     }  
  123.   
  124.     /** 
  125.      * Returns true if the current download has been canceled or if there was no download in 
  126.      * progress on this image view. 
  127.      * Returns false if the download in progress deals with the same url. The download is not 
  128.      * stopped in that case. 
  129.      */  
  130.     private static boolean cancelPotentialDownload(String url, ImageView imageView) {  
  131.         BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);  
  132.   
  133.         if (bitmapDownloaderTask != null) {  
  134.             String bitmapUrl = bitmapDownloaderTask.url;  
  135.             if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) {  
  136.                 bitmapDownloaderTask.cancel(true);  
  137.             } else {  
  138.                 // The same URL is already being downloaded.  
  139.                 return false;  
  140.             }  
  141.         }  
  142.         return true;  
  143.     }  
  144.   
  145.     /** 
  146.      * @param imageView Any imageView 
  147.      * @return Retrieve the currently active download task (if any) associated with this imageView. 
  148.      * null if there is no such task. 
  149.      */  
  150.     private static BitmapDownloaderTask getBitmapDownloaderTask(ImageView imageView) {  
  151.         if (imageView != null) {  
  152.             Drawable drawable = imageView.getDrawable();  
  153.             if (drawable instanceof DownloadedDrawable) {  
  154.                 DownloadedDrawable downloadedDrawable = (DownloadedDrawable)drawable;  
  155.                 return downloadedDrawable.getBitmapDownloaderTask();  
  156.             }  
  157.         }  
  158.         return null;  
  159.     }  
  160.   
  161.     Bitmap downloadBitmap(String url) {  
  162.         final int IO_BUFFER_SIZE = 4 * 1024;  
  163.   
  164.         // AndroidHttpClient is not allowed to be used from the main thread  
  165.         final HttpClient client = (mode == Mode.NO_ASYNC_TASK) ? new DefaultHttpClient() :  
  166.             AndroidHttpClient.newInstance("Android");  
  167.         final HttpGet getRequest = new HttpGet(url);  
  168.   
  169.         try {  
  170.             HttpResponse response = client.execute(getRequest);  
  171.             final int statusCode = response.getStatusLine().getStatusCode();  
  172.             if (statusCode != HttpStatus.SC_OK) {  
  173.                 Log.w("ImageDownloader", "Error " + statusCode +  
  174.                         " while retrieving bitmap from " + url);  
  175.                 return null;  
  176.             }  
  177.   
  178.             final HttpEntity entity = response.getEntity();  
  179.             if (entity != null) {  
  180.                 InputStream inputStream = null;  
  181.                 try {  
  182.                     inputStream = entity.getContent();  
  183.                     // return BitmapFactory.decodeStream(inputStream);  
  184.                     // Bug on slow connections, fixed in future release.  
  185.                     return BitmapFactory.decodeStream(new FlushedInputStream(inputStream));  
  186.                 } finally {  
  187.                     if (inputStream != null) {  
  188.                         inputStream.close();  
  189.                     }  
  190.                     entity.consumeContent();  
  191.                 }  
  192.             }  
  193.         } catch (IOException e) {  
  194.             getRequest.abort();  
  195.             Log.w(LOG_TAG, "I/O error while retrieving bitmap from " + url, e);  
  196.         } catch (IllegalStateException e) {  
  197.             getRequest.abort();  
  198.             Log.w(LOG_TAG, "Incorrect URL: " + url);  
  199.         } catch (Exception e) {  
  200.             getRequest.abort();  
  201.             Log.w(LOG_TAG, "Error while retrieving bitmap from " + url, e);  
  202.         } finally {  
  203.             if ((client instanceof AndroidHttpClient)) {  
  204.                 ((AndroidHttpClient) client).close();  
  205.             }  
  206.         }  
  207.         return null;  
  208.     }  
  209.   
  210.     /* 
  211.      * An InputStream that skips the exact number of bytes provided, unless it reaches EOF. 
  212.      */  
  213.     static class FlushedInputStream extends FilterInputStream {  
  214.         public FlushedInputStream(InputStream inputStream) {  
  215.             super(inputStream);  
  216.         }  
  217.   
  218.         @Override  
  219.         public long skip(long n) throws IOException {  
  220.             long totalBytesSkipped = 0L;  
  221.             while (totalBytesSkipped < n) {  
  222.                 long bytesSkipped = in.skip(n - totalBytesSkipped);  
  223.                 if (bytesSkipped == 0L) {  
  224.                     int b = read();  
  225.                     if (b < 0) {  
  226.                         break;  // we reached EOF  
  227.                     } else {  
  228.                         bytesSkipped = 1; // we read one byte  
  229.                     }  
  230.                 }  
  231.                 totalBytesSkipped += bytesSkipped;  
  232.             }  
  233.             return totalBytesSkipped;  
  234.         }  
  235.     }  
  236.   
  237.     /** 
  238.      * The actual AsyncTask that will asynchronously download the image. 
  239.      */  
  240.     class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> {  
  241.         private String url;  
  242.         private final WeakReference<ImageView> imageViewReference;  
  243.   
  244.         public BitmapDownloaderTask(ImageView imageView) {  
  245.             imageViewReference = new WeakReference<ImageView>(imageView);  
  246.         }  
  247.   
  248.         /** 
  249.          * Actual download method. 
  250.          */  
  251.         @Override  
  252.         protected Bitmap doInBackground(String... params) {  
  253.             url = params[0];  
  254.             return downloadBitmap(url);  
  255.         }  
  256.   
  257.         /** 
  258.          * Once the image is downloaded, associates it to the imageView 
  259.          */  
  260.         @Override  
  261.         protected void onPostExecute(Bitmap bitmap) {  
  262.             if (isCancelled()) {  
  263.                 bitmap = null;  
  264.             }  
  265.   
  266.             addBitmapToCache(url, bitmap);  
  267.   
  268.             if (imageViewReference != null) {  
  269.                 ImageView imageView = imageViewReference.get();  
  270.                 BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);  
  271.                 // Change bitmap only if this process is still associated with it  
  272.                 // Or if we don‘t use any bitmap to task association (NO_DOWNLOADED_DRAWABLE mode)  
  273.                 if ((this == bitmapDownloaderTask) || (mode != Mode.CORRECT)) {  
  274.                     imageView.setImageBitmap(bitmap);  
  275.                 }  
  276.             }  
  277.         }  
  278.     }  
  279.   
  280.   
  281.     /** 
  282.      * A fake Drawable that will be attached to the imageView while the download is in progress. 
  283.      * 
  284.      * <p>Contains a reference to the actual download task, so that a download task can be stopped 
  285.      * if a new binding is required, and makes sure that only the last started download process can 
  286.      * bind its result, independently of the download finish order.</p> 
  287.      */  
  288.     static class DownloadedDrawable extends ColorDrawable {  
  289.         private final WeakReference<BitmapDownloaderTask> bitmapDownloaderTaskReference;  
  290.   
  291.         public DownloadedDrawable(BitmapDownloaderTask bitmapDownloaderTask) {  
  292.             super(Color.BLACK);  
  293.             bitmapDownloaderTaskReference =  
  294.                 new WeakReference<BitmapDownloaderTask>(bitmapDownloaderTask);  
  295.         }  
  296.   
  297.         public BitmapDownloaderTask getBitmapDownloaderTask() {  
  298.             return bitmapDownloaderTaskReference.get();  
  299.         }  
  300.     }  
  301.   
  302.     public void setMode(Mode mode) {  
  303.         this.mode = mode;  
  304.         clearCache();  
  305.     }  
  306.   
  307.       
  308.     /* 
  309.      * Cache-related fields and methods. 
  310.      *  
  311.      * We use a hard and a soft cache. A soft reference cache is too aggressively cleared by the 
  312.      * Garbage Collector. 
  313.      */  
  314.       
  315.     private static final int HARD_CACHE_CAPACITY = 10;  
  316.     private static final int DELAY_BEFORE_PURGE = 10 * 1000; // in milliseconds  
  317.   
  318.     // Hard cache, with a fixed maximum capacity and a life duration  
  319.     private final HashMap<String, Bitmap> sHardBitmapCache =  
  320.         new LinkedHashMap<String, Bitmap>(HARD_CACHE_CAPACITY / 2, 0.75f, true) {  
  321.         @Override  
  322.         protected boolean removeEldestEntry(LinkedHashMap.Entry<String, Bitmap> eldest) {  
  323.             if (size() > HARD_CACHE_CAPACITY) {  
  324.                 // Entries push-out of hard reference cache are transferred to soft reference cache  
  325.                 sSoftBitmapCache.put(eldest.getKey(), new SoftReference<Bitmap>(eldest.getValue()));  
  326.                 return true;  
  327.             } else  
  328.                 return false;  
  329.         }  
  330.     };  
  331.   
  332.     // Soft cache for bitmaps kicked out of hard cache  
  333.     private final static ConcurrentHashMap<String, SoftReference<Bitmap>> sSoftBitmapCache =  
  334.         new ConcurrentHashMap<String, SoftReference<Bitmap>>(HARD_CACHE_CAPACITY / 2);  
  335.   
  336.     private final Handler purgeHandler = new Handler();  
  337.   
  338.     private final Runnable purger = new Runnable() {  
  339.         public void run() {  
  340.             clearCache();  
  341.         }  
  342.     };  
  343.   
  344.     /** 
  345.      * Adds this bitmap to the cache. 
  346.      * @param bitmap The newly downloaded bitmap. 
  347.      */  
  348.     private void addBitmapToCache(String url, Bitmap bitmap) {  
  349.         if (bitmap != null) {  
  350.             synchronized (sHardBitmapCache) {  
  351.                 sHardBitmapCache.put(url, bitmap);  
  352.             }  
  353.         }  
  354.     }  
  355.   
  356.     /** 
  357.      * @param url The URL of the image that will be retrieved from the cache. 
  358.      * @return The cached bitmap or null if it was not found. 
  359.      */  
  360.     private Bitmap getBitmapFromCache(String url) {  
  361.         // First try the hard reference cache  
  362.         synchronized (sHardBitmapCache) {  
  363.             final Bitmap bitmap = sHardBitmapCache.get(url);  
  364.             if (bitmap != null) {  
  365.                 // Bitmap found in hard cache  
  366.                 // Move element to first position, so that it is removed last  
  367.                 sHardBitmapCache.remove(url);  
  368.                 sHardBitmapCache.put(url, bitmap);  
  369.                 return bitmap;  
  370.             }  
  371.         }  
  372.   
  373.         // Then try the soft reference cache  
  374.         SoftReference<Bitmap> bitmapReference = sSoftBitmapCache.get(url);  
  375.         if (bitmapReference != null) {  
  376.             final Bitmap bitmap = bitmapReference.get();  
  377.             if (bitmap != null) {  
  378.                 // Bitmap found in soft cache  
  379.                 return bitmap;  
  380.             } else {  
  381.                 // Soft reference has been Garbage Collected  
  382.                 sSoftBitmapCache.remove(url);  
  383.             }  
  384.         }  
  385.   
  386.         return null;  
  387.     }  
  388.    
  389.     /** 
  390.      * Clears the image cache used internally to improve performance. Note that for memory 
  391.      * efficiency reasons, the cache will automatically be cleared after a certain inactivity delay. 
  392.      */  
  393.     public void clearCache() {  
  394.         sHardBitmapCache.clear();  
  395.         sSoftBitmapCache.clear();  
  396.     }  
  397.   
  398.     /** 
  399.      * Allow a new delay before the automatic cache clear is done. 
  400.      */  
  401.     private void resetPurgeTimer() {  
  402.         purgeHandler.removeCallbacks(purger);  
  403.         purgeHandler.postDelayed(purger, DELAY_BEFORE_PURGE);  
  404.     }  
  405. }  



里面有一些图片加载的方式方法,都很可取,不过对于ListView的优化而言,还应配合列表滚动监听来写。也就是说,当列表停止滚动,手离开屏幕的时候,再加载大数据,例如图片。稍后,我也会整理一篇,给大家提供参考借鉴。


源代码来自:http://code.google.com/p/android-imagedownloader/

滚动加载的例子:http://www.iteye.com/topic/1118828

 

摘自:http://blog.csdn.net/xyz_fly/article/details/7864076

Android编程之图片(异步)加载类,,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。