android picasso 三级缓存,Android中图片的三级缓存浅析

图片的三级缓存机制一般是指应用加载图片的时候,分别去访问内存,文件和网络而获取图片数据的一种行为。以下内容只是简单的介绍了三级缓存的思想和大致流程,还有很多细节未进行处理,如果想深入研究可以在Github上找Picasso的源码进行研究,谢谢。

一、三级缓存流程图

97455f080065

三级缓存流程图

二、代码框架搭建

这里我仿造Picasso的加载图片代码,也做出了with,load,into等方法。

2.1 with(context)

这个方法传入上下文,返回ImageManager对象。

/**

* 初始化对象

*

* @param context

* @return

*/

public static ImageManager with(Context context) {

mContext = context;

return getInstance();

}

因为ImageManager会不断的调用,所以要做成单利。

/**

* 获取对象的单利

*

* @return

*/

private static ImageManager instance;

private static ImageManager getInstance() {

if (instance == null) {

instance = new ImageManager();

}

return instance;

}

2.2 load(url)

这个方法返回一个自定义的RequestCreator内部类,对图片的操作都在这个内部类中进行。

/**

* 加载图片的url地址,返回RequestCreator对象

*

* @param url

* @return

*/

public RequestCreator load(String url) {

return new RequestCreator(url);

}

RequestCreator的构造方法中接收传入的url 。

// 初始化图片的url地址

public RequestCreator(String url) {

this.url = url;

}

2.3 into(imageview)

这是RequestCreator类的方法,也是工具类的核心方法,这个方法里进行图片的三个缓存处理。

三、内存缓存

3.1 Java中对象的四种引用类型介绍

强引用

Java中所有new出来的对象都是强引用类型,回收的时候,GC宁愿抛出OOM异常,也不回收它。

Map mImageCache = new HashMap<>();

软引用,SoftReference

内存足够时,不回收。内存不够时,就回收。这里使用这种方式缓存对象。

Map> mImageCache = new HashMap<>();

弱引用,WeakReference

GC一出来工作就回收它。

虚引用,PhantomReference

用完就消失。

3.2 使用LruCache类来做缓存

LruCache其实是一个Hash表,内部使用的是LinkedHashMap存储数据。使用LruCache类可以规定缓存内存的大小,并且这个类内部使用到了最近最少使用算法来管理缓存内存。

LruCache> mImageCache = new LruCache<>(1024 * 1024 * 4);

3.3 代码实现内存缓存

创建缓存集合

/**

* 内存储存图片的集合

* 使用lrucache缓存图片,这里不能申明在方法里,不然会被覆盖掉

* 使用软引用类型对象

* 4兆的大小作为缓存

*/

private LruCache> mImageCache = new LruCache<>(1024 * 1024 * 4);

访问内存时先从集合中取出软引用,获取BitMap

// 1 去内存之中找,有就显示,没有就往下走

SoftReference reference = mImageCache.get(url);

Bitmap cacheBitmap;

if(reference != null){

cacheBitmap = reference.get();

// 有就显示图片

imageView.setImageBitmap(cacheBitmap);

Log.d("RequestCreator:", "内存中有图片显示");

// 不往下走了

return;

}

如果缓存集合中的数据为空,就继续往下走。

四、文件缓存

4.1 缓存文件存储的路径设定

存储的路径首先要考虑SD卡的缓存目录,当SD卡不存在时,就只能存到内部存储的缓存目录了。

/**

* 获取缓存路径目录

*/

private File getCacheDir() {

// 获取保存的文件夹路径

File file;

if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) {

// 有SD卡就保存到sd卡

file = mContext.getExternalCacheDir();

} else {

// 没有就保存到内部储存

file = mContext.getCacheDir();

}

return file;

}

4.2 解析文件生成Bitmap对象

存储的文件的名字截取URL中的名字。

文件名使用Md5加密。

/**

* 从文件中获取bitmap

*

* @return

*/

private Bitmap getBitmapFromFile() {

// 从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;

}

}

4.3 判断是否有缓存

有缓存则读取出来显示,并且将缓存存入内存,没有就继续往下走。

// 2 去本地硬盘中找,有就显示,没有就继续往下走

// 将文件转换成bitmap对象

Bitmap diskBitmap = getBitmapFromFile();

if (diskBitmap != null) {

// 本地磁盘有就显示图片

imageView.setImageBitmap(diskBitmap);

// 保存到内存中去

mImageCache.put(url, new SoftReference(diskBitmap));

Log.d("RequestCreator:", "磁盘中有图片显示");

// 不往下走了

return;

}

五、联网加载

5.1 简单线程池处理耗时的网络请求

创建线程池对象

/**

* 构建出线程池,5条线程

*/

private ExecutorService mExecutorService = Executors.newFixedThreadPool(5);

提交任务,让RequestCreator实现Runnable接口,run方法中执行任务

// 3 联网请求数据

// 前面两步都没有的话就去联网加载数据

// 将从网络上获取的数据放到线程池去执行

mExecutorService.submit(this);

5.2 联网加载数据

使用HttpUrlConnection连接网络

// 子线程

// 处理网络请求

try {

URL 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);

mHandler.post(new Runnable() {

@Override

public void run() {

// 主线程

imageView.setImageBitmap(bm);

}

});

Log.d("RequestCreator:", "联网显示图片");

} else {

// 联网失败,显示失败图片

showError();

}

} catch (Exception e) {

e.printStackTrace();

// 发生异常显示失败图片

showError();

}

5.3 保存数据到内存和文件

使用缓存保存数据

// 3.1 保存到内存

mImageCache.put(url, new SoftReference<>(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);

六、细节处理

6.1 设置占位图

界面一上来加载图片时肯定是空白的,所以需要一张占位图。

RequestCreator类提供一个方法,将占位图片资源ID传进来。

/**

* 设置默认图片,占位图片

*

* @param holderResId

*/

public RequestCreator placeholder(int holderResId) {

this.holderResId = holderResId;

return this;

}

在into方法中,读取缓存之前,就让默认图显示。

// 一进来先设置占位图片

imageView.setImageResource(holderResId);

6.2 设置错误图片

加载数据出现错误和异常都显示错误图片。

/**

* 显示错误图片

*/

private void showError() {

mHandler.post(new Runnable() {

@Override

public void run() {

imageView.setImageResource(errorResId);

}

});

}

七、使用自己封装的小框架加载图片

使用很简单,和Picasso一样,一行代码就搞定。

// 使用自己封装的图片缓存工具类加载图片

ImageManager.with(mContext).load(imgUrl).placeholder(R.drawable.ic_default).error(R.drawable.ic_error).into(ivImage);

效果图

97455f080065

效果图

欢迎大家访问我的简书,博客和GitHub。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
用于类似图库,缓存,所困、缩略图 package com.example.cache; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.lang.ref.SoftReference; import java.util.HashMap; import java.util.Map; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BitmapFactory.Options; import android.util.DisplayMetrics; /** * 1.从内存加载 * 2.本地缓存加载 * 3.本地加载 * @author Administrator * */ public class LoadCacheImageTool { private Activity activity; private Map<String,SoftReference> cacheMap; public LoadCacheImageTool(Activity activity){ this.activity = activity; this.cacheMap = new HashMap<String, SoftReference>(); } public Bitmap loadCacheImage(String imagePath){ Bitmap bitmap = null; if (cacheMap.containsKey(imagePath)) { bitmap = cacheMap.get(imagePath).get(); if (bitmap!=null) { return bitmap; } } bitmap = loadLocalCacheImage(imagePath); cacheMap.put(imagePath, new SoftReference(bitmap)); return bitmap; } ///mnt/sdcard/bk.png ///mnt/sdcard/cache/bk.png.cache private Bitmap loadLocalCacheImage(String imagePath) { Bitmap bitmap = null; String cacheImagePath = getCacheImagePath(imagePath); File cacheFile = new File(cacheImagePath); if (!cacheFile.exists()) { bitmap = loadLocalBigImage(imagePath); saveToCacheDir(bitmap,cacheImagePath); }else{ try { bitmap = BitmapFactory.decodeStream(new FileInputStream(cacheFile)); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return bitmap; } private String getCacheImagePath(String imagePath) { String cacheDir = new File(imagePath).getParent()+"/cache/"; if (!new File(cacheDir).exists()) { new File(cacheDir).mkdirs(); } String newImageName = new File(imagePath).getName()+".cache"; String newImagePath = cacheDir+newImageNam

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值