缓存方式主要分为网络缓存,内存缓存,文件缓存
这里简单介绍一下后面两种的思路,使用内存缓存和使用文件缓存
- 缓存的基本原理,将从网络中得到的图片存储在本地,避免再次使用时从网络重新加载,可以增快加载速度,减少网络流量的消耗
##内存缓存
内存缓存主要分为两种方式
- 使用LruCache
- 使用HashMap
这两种方式一般结合使用
LruCache是Android给我们提供的工具类(内部实现用的LinkedHashMap),使用LruCache时,需给LruCache设置一个maxsize,当缓存图片的总大小超过maxsize之后,会执行LruCache的entryRemoved方法,此时可将被移除的oldValue存入HashMap中.
代码如下:
mLruCache = new LruCache<String, Bitmap>(memorySize) {
// 必须重写此方法,来测量Bitmap的大小
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
@Override
protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
// 当LruCache的内存容量满的时候会调用,将oldValue的元素移除出来腾出空间给新的元素加入
if (!TextUtils.isEmpty(key) && oldValue != null && !oldValue.isRecycled()) {
mWeakCache.put(key, new WeakReference<Bitmap>(oldValue));
}
}
};
HashMap的key采用和LruCache相同的key,value使用SoftReference或WeakReference.
SoftReference会在内存不足时被GC回收掉,WeakReference当GC一开始工作就会将其回收。
这两种一般会封装到一起使用,封装之后的使用统一的数据处理方法
put() put数据时,首先检查数据的key,value合法性,是否为null等等,2可以根据情况判断将要被缓存的Bitmap大小是否超过我们的单次最大限制(自己根据项目定)
public void put(String key, Bitmap value) {
if (TextUtils.isEmpty(key) || value == null) {
return;
}
int size = value.getRowBytes() * value.getHeight();// 4 * 宽 * 高
if (size > 1024 * 1024 * 3) {
return;
}
mLruCache.put(key, value);
}
get() get数据时,会首先根据key从LruCache中取get想要的数据,成功获取即返回,获取不到时再从HashMap中进行查找get
public Bitmap get(String key) {
if (TextUtils.isEmpty(key)) {
return null;
}
Bitmap bitmap = mLruCache.get(key);
if (bitmap != null) {
return bitmap;
}
WeakReference<Bitmap> reference = mWeakCache.get(key);
if (reference != null) {
return reference.get();
}
return null;
}
remove()和clear() 执行remove时,需要对应执行LruCache和HashMap的remove和clear方法
public void remove(String key) {
if (TextUtils.isEmpty(key)) {
return;
}
mLruCache.remove(key);
mWeakCache.remove(key);
}
public void clear() {
mLruCache.evictAll();
mWeakCache.clear();
}
##文件缓存
主要使用DiskLruCache
将从网络上下载的图片保存在手机SD卡中,以图片url的MD5值作为保存的文件名(key)
代码如下:
public class DiscCache {
private static final int MAX = 50 * 1024 * 1024;
private Context mContext;
private DiskLruCache mDiskLruCache;
public DiscCache(Context context) {
mContext = context;
String path = FileUtils.getBitmapCachePath(mContext);
final File cacheDir = new File(path);
if (!cacheDir.exists()) {
cacheDir.mkdirs();
}
ThreadManager.startRun(new Runnable() {
@Override
public void run() {
mDiskLruCache = DiskLruCache.open(cacheDir, 1, 1, MAX);
}
});
}
/**
* 增加获取缩略图Bitmap
*
* @param url
* @param config
* @return
*/
public Bitmap getThumbnailBitmap(String url, BitmapConfig config) {
Bitmap bitmap = getBitmapFromDisk(url, config);
try {
bitmap = LetvThumbnailUtils.getThumbnailBitmap(url);
if (bitmap == null) {
NativeThumbnail nativeThumbnail = new NativeThumbnail(url);
bitmap = nativeThumbnail.getVideoThumbnail(96, 96, 10);
}
if (bitmap != null && mDiskLruCache != null) {
DiskLruCache.Editor editor = mDiskLruCache.edit(MD5.MD5Encode(url));
if (editor != null) {
OutputStream outputStream = editor.newOutputStream(0);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
editor.commit();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
/**
* 从网络获取bitmap
*
* @param url
* @param config
* @return
*/
public Bitmap getBitmapFromNetwork(String url, BitmapConfig config) {
try {
DiskLruCache.Editor editor = null;
if (mDiskLruCache != null) {
editor = mDiskLruCache.edit(MD5.MD5Encode(url));
}
if (editor == null) {
return getBitmapFromNetworkWithoutLru(url, config);
}
OutputStream outputStream = editor.newOutputStream(0);
if (DownloaderFromHttp.download(url, outputStream)) {
editor.commit();
} else {
editor.abort();
}
return getBitmapFromDisk(url, config);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 从网络获取bitmap
*
* @param url
* @param config
* @return
*/
private Bitmap getBitmapFromNetworkWithoutLru(String url, BitmapConfig config) {
byte[] data = DownloaderFromHttp.download(url);
if (data != null && data.length > 0) {
ImgFileManager.saveImage(mContext, url, data);
if (config == null) {
return BitmapDecoder.decodeSampledBitmapFromByteArray(data, 0, data.length);
} else {
return BitmapDecoder
.decodeSampledBitmapFromByteArray(data, 0, data.length, config.width, config.height);
}
}
return null;
}
/**
* 从磁盘获取bitmap
*
* @param key
* @return
*/
public Bitmap getBitmapFromDisk(String key, BitmapConfig config) {
Snapshot snapshot = null;
try {
if (mDiskLruCache != null)
snapshot = mDiskLruCache.get(MD5.MD5Encode(key));
} catch (IOException e1) {
e1.printStackTrace();
}
if (snapshot == null) {
return getBitmapFromDiskWithoutLru(key, config);
}
FileInputStream fis = null;
ByteArrayOutputStream bos = null;
try {
fis = (FileInputStream) snapshot.getInputStream(0);
if (fis == null) {
return getBitmapFromDiskWithoutLru(key, config);
}
bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int n;
while ((n = fis.read(b)) != -1) {
bos.write(b, 0, n);
}
byte[] data = bos.toByteArray();
if (data == null)
return null;
if (config == null) {
return BitmapDecoder.decodeSampledBitmapFromByteArray(data, 0, data.length);
} else {
return BitmapDecoder
.decodeSampledBitmapFromByteArray(data, 0, data.length, config.width, config.height);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bos != null)
bos.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
if (fis != null)
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
/**
* 从磁盘获取bitmap
*
* @param key
* @return
*/
private Bitmap getBitmapFromDiskWithoutLru(String key, BitmapConfig config) {
byte[] data = ImgFileManager.getImage(mContext, key);
if (data == null)
return null;
if (config == null) {
return BitmapDecoder.decodeSampledBitmapFromByteArray(data, 0, data.length);
} else {
return BitmapDecoder.decodeSampledBitmapFromByteArray(data, 0, data.length, config.width, config.height);
}
}
/**
* 将缓存记录同步到journal文件中。
*/
public void fluchCache() {
if (mDiskLruCache != null) {
try {
mDiskLruCache.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void closeCache() {
if (mDiskLruCache != null) {
try {
mDiskLruCache.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}