ImageDownloader

来源:互联网 发布:手机显示e是什么网络 编辑:程序博客网 时间:2024/06/05 16:47

用于异步图片加载:

import java.io.FilterInputStream;import java.io.IOException;import java.io.InputStream;import java.lang.ref.SoftReference;import java.lang.ref.WeakReference;import java.util.HashMap;import java.util.LinkedHashMap;import java.util.concurrent.ConcurrentHashMap;import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.HttpStatus;import org.apache.http.client.HttpClient;import org.apache.http.client.methods.HttpGet;import org.apache.http.impl.client.DefaultHttpClient;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Color;import android.graphics.drawable.ColorDrawable;import android.graphics.drawable.Drawable;import android.os.AsyncTask;import android.os.Handler;import android.util.Log;import android.widget.ImageView;/** * This helper class download images from the Internet and binds those with the provided ImageView. * * <p>It requires the INTERNET permission, which should be added to your application's manifest * file.</p> * * A local cache of downloaded images is maintained internally to improve performance. */public class ImageDownloader {    private static final String TAG = ImageDownloader.class.getSimpleName();    private Drawable mDefaultDrawable = null;    private static ImageDownloader instance = null;    private ImageDownloader(){}    public static ImageDownloader getInstance(){if(instance == null){instance = new ImageDownloader();}return instance;}    //public enum Mode { NO_ASYNC_TASK, NO_DOWNLOADED_DRAWABLE, CORRECT }   // private Mode mode = Mode.NO_ASYNC_TASK;        /**     * Download the specified image from the Internet and binds it to the provided ImageView. The     * binding is immediate if the image is found in the cache and will be done asynchronously     * otherwise. A null bitmap will be associated to the ImageView if an error occurs.     *     * @param url The URL of the image to download.     * @param imageView The ImageView to bind the downloaded image to.     * @param defaultDrawable Show the Drawable for the ImageView when downloaded fail.     */    public void download(String url, ImageView imageView, Drawable defaultDrawable) {    setImageDefault(imageView, defaultDrawable);    if (url == null) {return;}        resetPurgeTimer();        Bitmap bitmap = getBitmapFromCache(url);        /*Log.w(TAG, "URL ====" + url);        Log.w(TAG, "bitmap ====" + bitmap);*/        if (bitmap == null) {            forceDownload(url, imageView);        } else {            cancelPotentialDownload(url, imageView);            imageView.setImageBitmap(bitmap);        }    }    /*     * Same as download but the image is always downloaded and the cache is not used.     * Kept private at the moment as its interest is not clear.       private void forceDownload(String url, ImageView view) {          forceDownload(url, view, null);       }     */    /**     * Same as download but the image is always downloaded and the cache is not used.     * Kept private at the moment as its interest is not clear.     */    private void forceDownload(String url, ImageView imageView) {        // State sanity: url is guaranteed to never be null in DownloadedDrawable and cache keys.        if (url == null) {            imageView.setImageDrawable(null);            return;        }        if (cancelPotentialDownload(url, imageView)) {                    BitmapDownloaderTask task = new BitmapDownloaderTask(imageView);             DownloadedDrawable downloadedDrawable = new DownloadedDrawable(task);             imageView.setImageDrawable(downloadedDrawable);             imageView.setMinimumHeight(5);//TODO:             task.execute(url);                           }    }    /**     * Returns true if the current download has been canceled or if there was no download in     * progress on this image view.     * Returns false if the download in progress deals with the same url. The download is not     * stopped in that case.     */    private static boolean cancelPotentialDownload(String url, ImageView imageView) {        BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);        if (bitmapDownloaderTask != null) {            String bitmapUrl = bitmapDownloaderTask.url;            if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) {                bitmapDownloaderTask.cancel(true);            } else {                // The same URL is already being downloaded.                return false;            }        }        return true;    }    /**     * @param imageView Any imageView     * @return Retrieve the currently active download task (if any) associated with this imageView.     * null if there is no such task.     */    private static BitmapDownloaderTask getBitmapDownloaderTask(ImageView imageView) {        if (imageView != null) {            Drawable drawable = imageView.getDrawable();            if (drawable instanceof DownloadedDrawable) {                DownloadedDrawable downloadedDrawable = (DownloadedDrawable)drawable;                return downloadedDrawable.getBitmapDownloaderTask();            }        }        return null;    }    Bitmap downloadBitmap(String url) {        //final int IO_BUFFER_SIZE = 4 * 1024;        // AndroidHttpClient is not allowed to be used from the main thread        final HttpClient client =  new DefaultHttpClient() ;           // AndroidHttpClient.newInstance("Android");        final HttpGet getRequest = new HttpGet(url);        try {            HttpResponse response = client.execute(getRequest);            final int statusCode = response.getStatusLine().getStatusCode();            if (statusCode != HttpStatus.SC_OK) {                Log.w(TAG, "Error " + statusCode + " while retrieving bitmap from " + url);                return null;            }            final HttpEntity entity = response.getEntity();            if (entity != null) {                InputStream inputStream = null;                try {                    inputStream = entity.getContent();                    // return BitmapFactory.decodeStream(inputStream);                    // Bug on slow connections, fixed in future release.                    return BitmapFactory.decodeStream(new FlushedInputStream(inputStream));                } finally {                    if (inputStream != null) {                        inputStream.close();                    }                    entity.consumeContent();                }            }        } catch (IOException e) {            getRequest.abort();            Log.w(TAG, "I/O error while retrieving bitmap from " + url, e);        } catch (IllegalStateException e) {            getRequest.abort();            Log.w(TAG, "Incorrect URL: " + url);        } catch (Exception e) {            getRequest.abort();            Log.w(TAG, "Error while retrieving bitmap from " + url, e);        } finally {            /*if ((client instanceof AndroidHttpClient)) {                ((AndroidHttpClient) client).close();            }*/        if (client != null && client.getConnectionManager() != null) {client.getConnectionManager().shutdown();}        }        return null;    }    /*     * An InputStream that skips the exact number of bytes provided, unless it reaches EOF.     */    static class FlushedInputStream extends FilterInputStream {        public FlushedInputStream(InputStream inputStream) {            super(inputStream);        }        @Override        public long skip(long n) throws IOException {            long totalBytesSkipped = 0L;            while (totalBytesSkipped < n) {                long bytesSkipped = in.skip(n - totalBytesSkipped);                if (bytesSkipped == 0L) {                    int b = read();                    if (b < 0) {                        break;  // we reached EOF                    } else {                        bytesSkipped = 1; // we read one byte                    }                }                totalBytesSkipped += bytesSkipped;            }            return totalBytesSkipped;        }    }    /**     * The actual AsyncTask that will asynchronously download the image.     */    class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> {        private String url;        private final WeakReference<ImageView> imageViewReference;        public BitmapDownloaderTask(ImageView imageView) {            imageViewReference = new WeakReference<ImageView>(imageView);        }        /**         * Actual download method.         */        @Override        protected Bitmap doInBackground(String... params) {            url = params[0];            return downloadBitmap(url);        }        /**         * Once the image is downloaded, associates it to the imageView         */        @Override        protected void onPostExecute(Bitmap bitmap) {                            if (isCancelled()) {                bitmap = null;            }                        addBitmapToCache(url, bitmap);            if (imageViewReference != null) {                ImageView imageView = imageViewReference.get();                BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);                // Change bitmap only if this process is still associated with it                // Or if we don't use any bitmap to task association (NO_DOWNLOADED_DRAWABLE mode)                if (this == bitmapDownloaderTask) {                                if (bitmap != null) {                imageView.setImageBitmap(bitmap);        }else {imageView.setImageDrawable(mDefaultDrawable);//设置默认的图标}                }                            }        }    }    /**     * A fake Drawable that will be attached to the imageView while the download is in progress.     *     * <p>Contains a reference to the actual download task, so that a download task can be stopped     * if a new binding is required, and makes sure that only the last started download process can     * bind its result, independently of the download finish order.</p>     */    static class DownloadedDrawable extends ColorDrawable {        private final WeakReference<BitmapDownloaderTask> bitmapDownloaderTaskReference;        public DownloadedDrawable(BitmapDownloaderTask bitmapDownloaderTask) {            super(Color.TRANSPARENT);            bitmapDownloaderTaskReference = new WeakReference<BitmapDownloaderTask>(bitmapDownloaderTask);        }        public BitmapDownloaderTask getBitmapDownloaderTask() {            return bitmapDownloaderTaskReference.get();        }    }        /*     * Cache-related fields and methods.     *      * We use a hard and a soft cache. A soft reference cache is too aggressively cleared by the     * Garbage Collector.     */        private static final int HARD_CACHE_CAPACITY = 10;    private static final int DELAY_BEFORE_PURGE = 10 * 1000; // in milliseconds    // Hard cache, with a fixed maximum capacity and a life duration    private final HashMap<String, Bitmap> sHardBitmapCache = new LinkedHashMap<String, Bitmap>(HARD_CACHE_CAPACITY / 2, 0.75f, true) {private static final long serialVersionUID = 1L;@Override        protected boolean removeEldestEntry(LinkedHashMap.Entry<String, Bitmap> eldest) {            if (size() > HARD_CACHE_CAPACITY) {                // Entries push-out of hard reference cache are transferred to soft reference cache                sSoftBitmapCache.put(eldest.getKey(), new SoftReference<Bitmap>(eldest.getValue()));                return true;            } else                return false;        }    };    // Soft cache for bitmaps kicked out of hard cache    private final static ConcurrentHashMap<String, SoftReference<Bitmap>> sSoftBitmapCache =        new ConcurrentHashMap<String, SoftReference<Bitmap>>(HARD_CACHE_CAPACITY / 2);    private final Handler purgeHandler = new Handler();    private final Runnable purger = new Runnable() {        public void run() {            clearCache();        }    };    /**     * Adds this bitmap to the cache.     * @param bitmap The newly downloaded bitmap.     */    private void addBitmapToCache(String url, Bitmap bitmap) {        if (bitmap != null) {            synchronized (sHardBitmapCache) {                sHardBitmapCache.put(url, bitmap);            }        }    }    /**     * @param url The URL of the image that will be retrieved from the cache.     * @return The cached bitmap or null if it was not found.     */    private Bitmap getBitmapFromCache(String url) {        // First try the hard reference cache        synchronized (sHardBitmapCache) {            final Bitmap bitmap = sHardBitmapCache.get(url);            if (bitmap != null) {                // Bitmap found in hard cache                // Move element to first position, so that it is removed last                sHardBitmapCache.remove(url);                sHardBitmapCache.put(url, bitmap);                return bitmap;            }        }        // Then try the soft reference cache        SoftReference<Bitmap> bitmapReference = sSoftBitmapCache.get(url);        if (bitmapReference != null) {            final Bitmap bitmap = bitmapReference.get();            if (bitmap != null) {                // Bitmap found in soft cache                return bitmap;            } else {                // Soft reference has been Garbage Collected                sSoftBitmapCache.remove(url);            }        }        return null;    }     /**     * Clears the image cache used internally to improve performance. Note that for memory     * efficiency reasons, the cache will automatically be cleared after a certain inactivity delay.     */    private void clearCache() {        sHardBitmapCache.clear();        sSoftBitmapCache.clear();    }    /**     * Allow a new delay before the automatic cache clear is done.     */    private void resetPurgeTimer() {        purgeHandler.removeCallbacks(purger);        purgeHandler.postDelayed(purger, DELAY_BEFORE_PURGE);    }        /**     * Description: 设置默认图标    * @param imageView    * @param drawable 如果为null, 那么当图标下载失败的时候,显示的图标则为空白, 否则显示设置的图标。     */    private void setImageDefault(ImageView imageView ,Drawable drawable) {    this.mDefaultDrawable = drawable;if (imageView != null) {imageView.setImageDrawable(drawable);}}    }

在Adapter中进行调用ImageDownloader.getInstance().download( url ,holder.imageView,getContext().getResources().getDrawable(R.drawable.default_icon));


原文出处 : http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html


原创粉丝点击