最近写了一个仿Picasso框架,实现简单的图片三级缓存,主要使用了SoftReference软引用,LruCache实现内存缓存,ExecutorService线程池进行线程的控制,这样更好的处理线程数量,防止线程过多,造成内存溢出。
大家可以直接使用:ImageManager.with(this).load("url").error(填写加载错误的图片).placeholder(填写加载中显示的图片).into(传人ImageView控件);
/**
* picasso框架,实现简单的图片三级缓存处理
* */
public class ImageManager {
private static Context mContext;
/**
* 构建出线程池,5条线程
* */
private ExecutorService executorService = Executors.newFixedThreadPool(5);
/**
* 内存储存图片的集合 使用lrucache缓存图片,这里不能申明在方法里,不然会被覆盖掉 4兆的大小作为缓存 SoftReference
* 为软引用、内存不足时,系统自动回收。
* */
private LruCache<String, SoftReference<Bitmap>> imageCache = new LruCache<String, SoftReference<Bitmap>>(
1024 * 1024 * 4);
private Handler handler = new Handler();
/**
* 获取对象的单例模式
* */
private static ImageManager instance;
private static ImageManager getInstance() {
if (instance == null) {
instance = new ImageManager();
}
return instance;
}
/***
* 初始化对象
*
* @param context
* @return
*/
public static ImageManager with(Context context) {
mContext = context;
return getInstance();
}
/***
* 加载图片的url地址,返回RequestCreator对象
*
* @param url
* @return
*/
public RequestCreatorRunnble load(String url) {
return new RequestCreatorRunnble(url);
}
/**
* 创建者
* */
public class RequestCreatorRunnble implements Runnable {
String url;
int holderResId;
int errorResId;
ImageView imageView;
// 初始化图片的url地址
public RequestCreatorRunnble(String url) {
this.url = url;
}
/***
* 设置默认图片,占位图片
*
* @param holderResId
* @return
*/
public RequestCreatorRunnble placeholder(int holderResId) {
this.holderResId = holderResId;
return this;
}
/***
* 发生错误加载的图片
*
* @param errorResId
* @return
*/
public RequestCreatorRunnble error(int errorResId) {
this.errorResId = errorResId;
return this;
}
public void into(ImageView imageView) {
// 变成全局的
this.imageView = imageView;
// 一进来先设置占位图片
imageView.setImageResource(holderResId);
// 1.去内存之中在找,有就显示,没有就往下走
SoftReference<Bitmap> reference = imageCache.get(url);
Bitmap cacheBitmap;
if (reference != null) {
cacheBitmap = reference.get();
// 有图片就显示图片
imageView.setImageBitmap(cacheBitmap);
return;
}
// 2.去本地硬盘中找,有就显示,没有就继续往下走
// 将文件转换成bitmap对象
Bitmap diskBitmap = getBitmapFile();
if (diskBitmap == null) {
// 本地磁盘有就显示图片
imageView.setImageBitmap(diskBitmap);
// 保存到内存中去
imageCache.put(url, new SoftReference<Bitmap>(diskBitmap));
return;
}
// 3.连接网络请求数据
// 前面两步都没有的话就去联网加载数据
// 将从网络上获取的数据放到线程池去执行
executorService.submit(this);
}
@Override
public void run() {
// 子线程
// 处理网络请求
URL loadUrl;
try {
loadUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection) loadUrl
.openConnection();
// 设置请求方式
conn.setRequestMethod("GET");
// 设置请求时间
conn.setConnectTimeout(2000);
if (conn.getResponseCode() == 200) {
InputStream is = conn.getInputStream();
// 获取到图片进行显示
final Bitmap bm = BitmapFactory.decodeStream(is);
handler.post(new Runnable() {
@Override
public void run() {
// 主线程
imageView.setImageBitmap(bm);
}
});
// 3.1保存到内存中
imageCache.put(url, new SoftReference<Bitmap>(bm));
// 3.2保存到磁盘
// 从url中获取文件名字
String fileName = url.substring(url.lastIndexOf("/") + 1);
// 获取存储路径
File file = new File(getCacheDir(),
MD5Util.encodeMd5(fileName));
FileOutputStream os = new FileOutputStream(file);
// 将图片转换为文件进行存储
bm.compress(Bitmap.CompressFormat.JPEG, 100, os);
} else {
// 联网失败,显示失败图片
showError();
}
} catch (Exception e) {
e.printStackTrace();
// 显示错误的图片
showError();
}
}
/***
* 获取文件中的图片
*
* @return
*/
private Bitmap getBitmapFile() {
// 从url中获取文件名字
String fileName = url.substring(url.lastIndexOf("/") + 1);
File file = new File(getCacheDir(), MD5Util.encodeMd5(fileName));
// 确保路径没有问题
if (file.exists() && file.length() > 0) {
// 返回图片
return BitmapFactory.decodeFile(file.getAbsolutePath());
} else {
return null;
}
}
/***
* 显示错误的图片
*/
private void showError() {
handler.post(new Runnable() {
@Override
public void run() {
imageView.setImageResource(errorResId);
}
});
}
/***
* 读取缓存路径目录
*
* @return
*/
private File getCacheDir() {
// 获取保存的文件夹路径
File file;
if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) {
// 有SD卡就保存到SD卡
file = mContext.getExternalCacheDir();
} else {
// 没有就保存到内部存储
file = mContext.getCacheDir();
}
return file;
}
}
}