我们在RecyclerView中大量显示ImageView图片的时候,会发现从本地加载图片显示在ImageView特别的慢,甚至会内存溢出,这个时候我们可以使用LruCache来缓存本地图片bitmap数据,这样在加载时就会特别快了。
下面是LruCache图片缓存的方法。永远不用担心Bitmap导致内存溢出,因为LruCache使用的是你系统的剩余内存,你可以自己分配多少内存给它,代码如下:
package com.xuanyin.homektv.util;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Environment;
import android.widget.ImageView;
import android.util.LruCache;
import java.util.LinkedHashMap;
import java.util.concurrent.ExecutorService;
import java.util.Map;
import java.util.concurrent.Executors;
import java.io.File;
public class ImageUtils {
private static LruCache<String, Bitmap> mCaches;
/**
* 定义上下文对象
*/
private Context mContext;
private static Handler mHandler;
//声明线程池,全局只有一个线程池,所有访问网络图片,只有这个池子去访问。
private static ExecutorService mPool;
//解决错位问题,定义一个存标记的集合
private Map<ImageView, String> mTags = new LinkedHashMap<ImageView, String>();
public ImageUtils(Context context) {
this.mContext = context;
if (mCaches == null) {
//申请内存空间
int maxSize = (int) (Runtime.getRuntime().freeMemory() / 4);
//实例化LruCache
mCaches = new LruCache<String, Bitmap>(maxSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
//判断添加进入的value的占用内存的大小
//这里默认sizeOf是返回1,不占用,内存会不够用,所以要给它一个具体占用内存的大小
//return super.sizeOf(key, value);
//获取Bitmap的大小
return value.getRowBytes() * value.getHeight();
}
};
}
if (mHandler == null) {
//实例化Handler
mHandler = new Handler();
}
if (mPool == null) {
//创建固定大小的线程池
mPool = Executors.newFixedThreadPool(3);
//创建一个缓存的线程池,生产者和消费者,一个线程生产,必须得消费完成后再生产
/*Executors.newCachedThreadPool();
Executors.newSingleThreadExecutor();//创建一个单线程池
Executors.newScheduledThreadPool();//创建一个计划的任务池*/
}
}
/**
* 给imageView加载url对应的图片
*
* @param iv
* @param url
*/
public void display(ImageView iv, String url) {
System.out.println("加载url对应的图片:" + url);
//1.从内存中获取
Bitmap bitmap = mCaches.get(url);
if (bitmap != null) {
//内存中有,显示图片
iv.setImageBitmap(bitmap);
System.out.println("加载url内存图片:" + url);
return;
}
//2.内存中没有,从本地获取
bitmap = loadFromLocal(url);
if (bitmap != null) {
//本地有,显示
iv.setImageBitmap(bitmap);
return;
}
}
/**
* 从本地获取图片
*
* @param url
* @return bitmap
*/
private Bitmap loadFromLocal(String url) {
//本地需要存储路径
//File file = getCacheFile(url);
File file = new File(url);
if (file.exists()) {
//本地有
//把文件解析成Bitmap
Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
//存储到内存
mCaches.put(url, bitmap);
return bitmap;
}
return null;
}
/**
* 获取缓存文件路径(缓存目录)
*
* @return 缓存的文件
*/
private File getCacheFile(String url) {
//获取当前的状态,Environment是环境变量
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
//挂载状态,sd卡存在
File dir = new File(Environment.getExternalStorageDirectory(),
"/Android/data/" + mContext.getPackageName() + "/icon");
if (!dir.exists()) {
//文件不存在,就创建
dir.mkdirs();
}
//此处的url可能会很长,一般会使用md5加密
return new File(dir, url);
} else {
File dir = new File(mContext.getCacheDir(), "/icon");
if (!dir.exists()) {
//文件不存在,就创建
dir.mkdirs();
}
return new File(dir, url);
}
}
}我们在RecyclerView中如果要显示图片,可以类似如下即可:
ImageUtils imageUtils = new ImageUtils(getContext()); imageUtils.display(imageView, "xxx.jpg");
小编发现Android中使用LruCache来缓存并显示图片,速度特别的快,比那个Glide快多了。