学习Android的人可能都会碰到过OOM的问题,特别是加载很多图片的时候很容易就OOM了。网上一搜,这类问题解答有很多,下面本人分享一下,对三级缓存加载图片的理解和一些工具类代码。
一、理解
三级缓存加载图片就是先从内存找图片,没有的话,再去本地存储里找图片,再没有的话,就只能网络上加载。所以我们要做的就是,第一次把图片从网上加载下来,就存进内存和本地,然后以后需要重新加载该图片的时候,就按照内存->本地->网络的顺序来进行加载。
二、代码实现
理解了思想,代码就很容易实现了。以下是本人写的一些工具类(PS: 由于代码比较简单,如有雷同,纯属巧合 * _ *)
/**
* 内存缓存工具类
*/
public class MemoryCacheUtil {
//使用LruCache来缓存图片
private LruCache<String, Bitmap> imageCache;
private static MemoryCacheUtil memoryCacheUtil;
private MemoryCacheUtil() {
long maxMemory = Runtime.getRuntime().maxMemory() / 8;
imageCache = new LruCache<String, Bitmap>((int) maxMemory) {
@Override
protected int sizeOf(String key, Bitmap value) {
int byteSize = value.getRowBytes() * value.getHeight();
return byteSize;
}
};
}
public static MemoryCacheUtil getInstance() {
if (memoryCacheUtil == null)
memoryCacheUtil = new MemoryCacheUtil();
return memoryCacheUtil;
}
//根据url获取图片
public Bitmap getImage(String url) {
if (url != null) {
return imageCache.get(url);
}
return null;
}
//保存图片
public void storeImage(String url, Bitmap bitmap) {
imageCache.put(url, bitmap);
}
}
/**
* 本地存储工具类
*/
public class LocalCacheUtil {
private static LocalCacheUtil localCacheUtil;
public final String CACHE_PATH = Environment
.getExternalStorageDirectory().getAbsolutePath()
+ File.separator + "MyImgCache";
private LocalCacheUtil() {
}
public static LocalCacheUtil getInstance() {
if (localCacheUtil == null)
localCacheUtil = new LocalCacheUtil();
return localCacheUtil;
}
//根据指定地址获取图片
public Bitmap getImage(String url) {
if (url != null) {
File file = new File(CACHE_PATH, url);
if (file.exists()) {
return BitmapFactory.decodeFile(file.getAbsolutePath());
}
}
return null;
}
//存储图片到本地
public void storeImage(String url, Bitmap bitmap) {
File file = new File(CACHE_PATH, url);
File parentFile = file.getParentFile();
if (!parentFile.exists()) {
parentFile.mkdirs();
}
try {
FileOutputStream fos = new FileOutputStream(file);
//把图片写进本地
// bitmap.compress(Bitmap.CompressFormat.PNG, 100,
// fos);
//这里对图片进行压缩,把大小控制在60kb以下
byte[] data = ImageUtil.getImageByteByCompress(bitmap, 60);
fos.write(data, 0, data.length);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//三级缓存工具类
public class ThreeCacheUtil {
/**
* 三级缓存加载图片
*
* @param iv 目标控件
* @param url 图片地址
*/
public static void loadImage(final ImageView iv, final String url) {
if (iv == null || url == null) return;
/**
* 先尝试从内存取图
*/
if (MemoryCacheUtil.getInstance().getImage(url) != null) {
iv.setImageBitmap(MemoryCacheUtil
.getInstance().getImage(url));
}
//内存没有,再尝试从本地存储取图
else if (LocalCacheUtil.getInstance().getImage(url) != null) {
iv.setImageBitmap(LocalCacheUtil
.getInstance().getImage(url));
//把加载好的图片写进内存,已便下次可以从内存取图
MemoryCacheUtil.getInstance().storeImage(url,
LocalCacheUtil.getInstance().getImage(url));
}
//本地都没有,就从网络上加载,这里用了Volley网络框架,对Volley不熟悉的朋友可能看下面代码会有点懵
else {
ImageLoader.ImageCache imageCache = new ImageLoader.ImageCache() {
@Override
public Bitmap getBitmap(String s) {
return MemoryCacheUtil.getInstance().getImage(url);
}
@Override
public void putBitmap(final String s, final Bitmap bitmap) {
final int width = iv.getWidth();
final int height = iv.getHeight();
//这个AsyncTask主要是用于压缩图片任务
new AsyncTask<Void, Void, Bitmap>() {
@Override
protected Bitmap doInBackground(Void... params) {
//这里对图片进行一些压缩处理,使得展示效果更佳
Bitmap bitmap1 = ImageUtil.getImageByScale(bitmap,
width, height, 100);
return bitmap1;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
//把加载好的图片存进内存
MemoryCacheUtil.getInstance().storeImage(url, bitmap);
//把加载好的图片存进本地
LocalCacheUtil.getInstance().storeImage(url, bitmap);
}
}.execute();
}
};
ImageLoader imageLoader = new ImageLoader(MyApplication
.getInstance().getRequestQueue(), imageCache);
ImageLoader.ImageListener listener = ImageLoader.getImageListener(iv,
R.drawable.icon_default, R.drawable.icon_default);
imageLoader.get(url, listener);
}
}
}
在图片加载的地方只要用一句
ThreeCacheUtil .loadImage(iv, url);
以上是本人对三级缓存加载图片的一些理解和应用,欢迎纠错和补充