Android编程之图片(异步)加载类
应某人之请,写一篇关于图片加载类。其实,网上有很多这样的类,而且比较推崇的是来自google中开源中的一篇。他写的比较好了,而且注意了内存优化,下面贴出它的图片下载类:
- /*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package com.example.android.imagedownloader;
- 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.net.http.AndroidHttpClient;
- import android.os.AsyncTask;
- import android.os.Handler;
- import android.util.Log;
- import android.widget.ImageView;
- 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;
- /**
- * 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 LOG_TAG = "ImageDownloader";
- 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.
- */
- public void download(String url, ImageView imageView) {
- resetPurgeTimer();
- Bitmap bitmap = getBitmapFromCache(url);
- 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)) {
- switch (mode) {
- case NO_ASYNC_TASK:
- Bitmap bitmap = downloadBitmap(url);
- addBitmapToCache(url, bitmap);
- imageView.setImageBitmap(bitmap);
- break;
- case NO_DOWNLOADED_DRAWABLE:
- imageView.setMinimumHeight(156);
- BitmapDownloaderTask task = new BitmapDownloaderTask(imageView);
- task.execute(url);
- break;
- case CORRECT:
- task = new BitmapDownloaderTask(imageView);
- DownloadedDrawable downloadedDrawable = new DownloadedDrawable(task);
- imageView.setImageDrawable(downloadedDrawable);
- imageView.setMinimumHeight(156);
- task.execute(url);
- break;
- }
- }
- }
- /**
- * 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 = (mode == Mode.NO_ASYNC_TASK) ? 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("ImageDownloader", "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(LOG_TAG, "I/O error while retrieving bitmap from " + url, e);
- } catch (IllegalStateException e) {
- getRequest.abort();
- Log.w(LOG_TAG, "Incorrect URL: " + url);
- } catch (Exception e) {
- getRequest.abort();
- Log.w(LOG_TAG, "Error while retrieving bitmap from " + url, e);
- } finally {
- if ((client instanceof AndroidHttpClient)) {
- ((AndroidHttpClient) client).close();
- }
- }
- 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) || (mode != Mode.CORRECT)) {
- imageView.setImageBitmap(bitmap);
- }
- }
- }
- }
- /**
- * 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.BLACK);
- bitmapDownloaderTaskReference =
- new WeakReference<BitmapDownloaderTask>(bitmapDownloaderTask);
- }
- public BitmapDownloaderTask getBitmapDownloaderTask() {
- return bitmapDownloaderTaskReference.get();
- }
- }
- public void setMode(Mode mode) {
- this.mode = mode;
- clearCache();
- }
- /*
- * 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) {
- @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.
- */
- public 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);
- }
- }
里面有一些图片加载的方式方法,都很可取,不过对于ListView的优化而言,还应配合列表滚动监听来写。也就是说,当列表停止滚动,手离开屏幕的时候,再加载大数据,例如图片。稍后,我也会整理一篇,给大家提供参考借鉴。
源代码来自:http://code.google.com/p/android-imagedownloader/
滚动加载的例子:http://www.iteye.com/topic/1118828
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。