一、概述:
现在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();
}
}