一、概述: 现在android应用中不可避免的要使用图片,有些图片是可以变化的,需要每次启动时从网络拉取,这种场景在有广告位的应用以及纯图片应用(比如百度美拍)中比较多。
现在有一个问题:假如每次启动的时候都从网络拉取图片的话,势必会消耗很多流量。在当前的状况下,对于非wifi用户来说,流量还是很贵的,一个很耗流量的应用,其用户数量级肯定要受到影响。当然,我想,向百度美拍这样的应用,必然也有其内部的图片缓存策略。总之,图片缓存是很重要而且是必须的。
二、实现原理: 实现图片缓存也不难,需要有相应的cache策略。这里我采用 内存-文件-网络 三层cache机制,其中内存缓存包括强引用缓存和软引用缓存(SoftReference),其实网络不算cache,这里姑且也把它划到缓存的层次结构中。当根据url向网络拉取图片的时候,先从内存中找,如果内存中没有,再从缓存文件中查找,如果缓存文件中也没有,再从网络上通过http请求拉取图片。在键值对(key-value)中,这个图片缓存的key是图片url的hash值,value就是bitmap。所以,按照这个逻辑,只要一个url被下载过,其图片就被缓存起来了。
三、如何使用
参数context,imageview,url以及默认站位图
ImageHelper.getInstance().display(mContext,mImageView,data.getImageUrl(),R.drawable.default_banner);
上源码............ 可直接cope
import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Environment; import android.os.Handler; import android.support.v4.util.LruCache; import android.widget.ImageView; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; /** * 图片三级缓存类 */ public class ImageHelper { // LRUCahce 池子 private static LruCache<String, Bitmap> mCache; private static Handler mHandler; private Context mContext; private int mDefaultImg; @SuppressLint("StaticFieldLeak") private static ImageHelper mBannerImageHelper; public static ImageHelper getInstance() { if (mBannerImageHelper == null) { synchronized (ImageHelper.class) { if (mBannerImageHelper == null) { mBannerImageHelper = new ImageHelper(); init(); } } } return mBannerImageHelper; } private static void init() { if (mCache == null) { // 最大使用的内存空间 int maxSize = (int) (Runtime.getRuntime().freeMemory() / 4); if (maxSize > 0) { mCache = new LruCache<String, Bitmap>(maxSize) { @Override protected int sizeOf(String key, Bitmap value) { return value.getRowBytes() * value.getHeight(); } }; } if (mHandler == null) { mHandler = new Handler(); } } } public void display(Context context, ImageView iv, String url, int defaultImg) { this.mDefaultImg = defaultImg; this.mContext = context; // 1.去内存中取 if (url != null) { Bitmap bitmap = mCache.get(url); if (bitmap != null) { // 直接显示 iv.setImageBitmap(bitmap); return; } // 2.去硬盘上取 bitmap = loadBitmapFromLocal(url); if (bitmap != null) { // 直接显示 iv.setImageBitmap(bitmap); return; } iv.setImageResource(mDefaultImg); // 3. 去网络获取图片 new Thread(new ImageLoadTask(iv, url)).start(); } else { iv.setImageResource(mDefaultImg); } } class ImageLoadTask implements Runnable { private String mUrl; private ImageView iv; private ImageLoadTask(ImageView iv, String url) { this.mUrl = url; this.iv = iv; } @Override public void run() { // HttpUrlconnection try { // 获取连接 HttpURLConnection conn = (HttpURLConnection) new URL(mUrl).openConnection(); conn.setConnectTimeout(30 * 1000);// 设置连接服务器超时时间 conn.setReadTimeout(30 * 1000);// 设置读取响应超时时间 // 连接网络 conn.connect(); // 获取响应码 int code = conn.getResponseCode(); if (200 == code) { InputStream is = conn.getInputStream(); // 将流转换为bitmap Bitmap bitmap = BitmapFactory.decodeStream(is); // 存储到本地 write2Local(mUrl, bitmap); // 存储到内存 mCache.put(mUrl, bitmap); mHandler.post(new Runnable() { @Override public void run() { display(mContext, iv, mUrl, mDefaultImg); } }); } } catch (Exception e) { // TODO Auto-generated catch block0 e.printStackTrace(); } } } /** * 本地种去去图片 * * @param url */ private Bitmap loadBitmapFromLocal(String url) { // 去找文件,将文件转换为bitmap String name; try { name = MD5Encoder.encode(url); File file = new File(getCacheDir(), name); if (file.exists()) { Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); // 存储到内存 mCache.put(url, bitmap); return bitmap; } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } private void write2Local(String url, Bitmap bitmap) { String name; FileOutputStream fos = null; try { name = MD5Encoder.encode(url); File file = new File(getCacheDir(), name); fos = new FileOutputStream(file); // 将图像写到流中 bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos); } catch (Exception e) { e.printStackTrace(); } finally { if (fos != null) { try { fos.close(); fos = null; } catch (IOException e) { e.printStackTrace(); } } } } private String getCacheDir() { String state = Environment.getExternalStorageState(); File dir = null; if (Environment.MEDIA_MOUNTED.equals(state)) { // 有sd卡 dir = new File(Environment.getExternalStorageDirectory(), "/Android/data/" + mContext.getPackageName() + "/icon"); } else { // 没有sd卡 dir = new File(mContext.getCacheDir(), "/icon"); } if (!dir.exists()) { dir.mkdirs(); } return dir.getAbsolutePath(); } }