图片加载,使用了内存缓存、文件缓存等方法。效果还不错。下图为加载图片时的流程图。
下面为该图片加载类:
package com.geniusgithub.lookaround.cache; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.Collections; import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import com.geniusgithub.lookaround.util.CommonLog; import com.geniusgithub.lookaround.util.LogFactory; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.util.Log; import android.widget.ImageView; /** * 图片下载类 * * @author Administrator * */ public class ImageLoaderEx { private static final CommonLog log = LogFactory.createLog(); private MemoryCache memoryCache = new MemoryCache(); private AbstractFileCache fileCache; private Map<ImageView, String> imageViews = Collections .synchronizedMap(new WeakHashMap<ImageView, String>()); // 线程池 private ExecutorService executorService; private int requestSize = 120; private Bitmap mDefaultBitmap = null; private boolean mIsLoadLocalBitmapQuick = false; /** * 构造函数 * * @param context */ public ImageLoaderEx(Context context) { fileCache = new FileCache(context); executorService = Executors.newFixedThreadPool(5); } /** * 设置图片大小 * * @param request_size */ public void setScaleParam(int request_size) { requestSize = request_size; log.e("setScaleParam requestSize = " + requestSize); } /** * 是否快速下载图片 * * @param flag */ public void setLoadLocalBitmapQuick(boolean flag) { mIsLoadLocalBitmapQuick = flag; } /** * 设置默认图片 * * @param drawable */ public void setDefaultBitmap(Drawable drawable) { if (drawable != null) { BitmapDrawable bd = (BitmapDrawable) drawable; mDefaultBitmap = bd.getBitmap(); } } /** * 最主要的方法 * * @param url * @param imageView * @param isLoadOnlyFromCache * @return */ public boolean DisplayImage(String url, ImageView imageView, boolean isLoadOnlyFromCache) { if (url == null || url.length() < 1 || imageView == null) { return false; } imageViews.put(imageView, url); // 先从内存缓存中查找 Bitmap bitmap = memoryCache.get(url); if (bitmap != null) { imageView.setImageBitmap(bitmap); return true; } // 如果直接从缓存文件加载 if (mIsLoadLocalBitmapQuick) { File f = fileCache.getFile(url); // 先从文件缓存中查找是否有 Bitmap b = null; if (f != null && f.exists()) { b = decodeFile(f); } if (b != null) { imageView.setImageBitmap(b); return true; } } if (mDefaultBitmap != null) { imageView.setImageBitmap(mDefaultBitmap); } if (!isLoadOnlyFromCache) { // 若没有的话则开启新线程加载图片 queuePhoto(url, imageView); } return false; } /** * 同步加载图片 * * @param url * @param imageView * @return */ public boolean syncLoadBitmap(String url, ImageView imageView) { if (url == null || url.length() < 1 || imageView == null) { return false; } queuePhoto(url, imageView); return true; } /** * 线程池启动线程加载图片 * * @param url * @param imageView */ private void queuePhoto(String url, ImageView imageView) { PhotoToLoad p = new PhotoToLoad(url, imageView); executorService.submit(new PhotosLoader(p)); } /** * 获取图片 * * @param url * @return */ private Bitmap getBitmap(String url) { File f = fileCache.getFile(url); // 先从文件缓存中查找是否有 Bitmap b = null; if (f != null && f.exists()) { b = decodeFile(f); } if (b != null) { return b; } // 最后从指定的url中下载图片 try { Bitmap bitmap = null; URL imageUrl = new URL(url); HttpURLConnection conn = (HttpURLConnection) imageUrl .openConnection(); conn.setConnectTimeout(30000); conn.setReadTimeout(30000); conn.setInstanceFollowRedirects(true); InputStream is = conn.getInputStream(); OutputStream os = new FileOutputStream(f); CopyStream(is, os); os.close(); bitmap = decodeFile(f); return bitmap; } catch (Exception ex) { Log.e("", "getBitmap catch Exception...\nmessage = " + ex.getMessage()); return null; } } /** * decode这个图片并且按比例缩放以减少内存消耗,虚拟机对每张图片的缓存大小也是有限制的 * * @param f * @return */ private Bitmap decodeFile(File f) { try { // decode image size BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; BitmapFactory.decodeStream(new FileInputStream(f), null, o); // Find the correct scale value. It should be the power of 2. int width_tmp = o.outWidth, height_tmp = o.outHeight; int scale = 1; while (true) { if (width_tmp / 2 < requestSize || height_tmp / 2 < requestSize) break; width_tmp /= 2; height_tmp /= 2; scale *= 2; } // log.e("w = " + width_tmp + ", h = " + height_tmp + ", scale = " + // scale); // decode with inSampleSize BitmapFactory.Options o2 = new BitmapFactory.Options(); o2.inSampleSize = scale; return BitmapFactory.decodeStream(new FileInputStream(f), null, o2); } catch (FileNotFoundException e) { } return null; } /** * 下载图片类 Task for the queue * * @author Administrator * */ private class PhotoToLoad { public String url; public ImageView imageView; public PhotoToLoad(String u, ImageView i) { url = u; imageView = i; } } /** * 图片下载线程执行函数 */ class PhotosLoader implements Runnable { PhotoToLoad photoToLoad; /** * 构造函数 */ PhotosLoader(PhotoToLoad photoToLoad) { this.photoToLoad = photoToLoad; } @Override public void run() { if (imageViewReused(photoToLoad)) { return; } Bitmap bmp = getBitmap(photoToLoad.url); memoryCache.put(photoToLoad.url, bmp); if (imageViewReused(photoToLoad)) return; BitmapDisplayer bd = new BitmapDisplayer(bmp, photoToLoad); // 更新的操作放在UI线程中 Activity a = (Activity) photoToLoad.imageView.getContext(); a.runOnUiThread(bd); } } /** * 防止图片错位 * * @param photoToLoad * @return */ boolean imageViewReused(PhotoToLoad photoToLoad) { String tag = imageViews.get(photoToLoad.imageView); if (tag == null || !tag.equals(photoToLoad.url)) return true; return false; } // 用于在UI线程中更新界面 class BitmapDisplayer implements Runnable { Bitmap bitmap; PhotoToLoad photoToLoad; public BitmapDisplayer(Bitmap b, PhotoToLoad p) { bitmap = b; photoToLoad = p; } public void run() { // log.e("BitmapDisplayer run..."); if (imageViewReused(photoToLoad)) return; if (bitmap != null) photoToLoad.imageView.setImageBitmap(bitmap); } } /** * 清楚缓存 */ public void clearCache() { memoryCache.clear(); fileCache.clear(); } /** * 拷贝接收到的数据 * * @param is * @param os */ public static void CopyStream(InputStream is, OutputStream os) { final int buffer_size = 1024; try { byte[] bytes = new byte[buffer_size]; for (;;) { int count = is.read(bytes, 0, buffer_size); if (count == -1) break; os.write(bytes, 0, count); } } catch (Exception ex) { Log.e("", "CopyStream catch Exception..."); } } }
使用该类的示例如下:
mImageLoader.DisplayImage(url, imageView, true);