android picasso 三级缓存,Android中图片的三级缓存浅析
图片的三级缓存机制一般是指应用加载图片的时候,分别去访问内存,文件和网络而获取图片数据的一种行为。以下内容只是简单的介绍了三级缓存的思想和大致流程,还有很多细节未进行处理,如果想深入研究可以在Github上找Picasso的源码进行研究,谢谢。
一、三级缓存流程图
三级缓存流程图
二、代码框架搭建
这里我仿造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);
效果图
效果图
欢迎大家访问我的简书,博客和GitHub。
android picasso 三级缓存,Android中图片的三级缓存浅析相关推荐
- Android 系统(173)---Android中图片的三级缓存
Android中图片的三级缓存 为什么要使用三级缓存 如今的 Android App 经常会需要网络交互,通过网络获取图片是再正常不过的事了 假如每次启动的时候都从网络拉取图片的话,势必会消耗很多流量 ...
- Android中图片的三级缓存策略
在开发过程中,经常会碰到进行请求大量的网络图片的样例.假设处理的不好.非常easy造成oom.对于避免oom的方法,无非就是进行图片的压缩.及时的回收不用的图片.这些看似简单可是处理起来事实上涉及的知 ...
- android三级缓存封装,Android 中图片的三级缓存详解
图片的三级缓存机制一般是指应用加载图片的时候,分别去访问内存,文件和网络而获取图片数据的一种行为. 一.三级缓存流程图 三级缓存流程图 二.代码框架搭建 这里我仿造Picasso[3]的加载图片代码, ...
- springboot整个缓存_SpringBoot中整合Redis(缓存篇)
实际开发中缓存处理是必须的,不可能我们每次客户端去请求一次服务器,服务器每次都要去数据库中进行查找,为什么要使用缓存?说到底是为了提高系统的运行速度.将用户频繁访问的内容存放在离用户最近,访问速度最快 ...
- android 常用机型尺寸_Android中图片大小与各种hdpi
前言 大家都知道开发android会涉及到UI的涉及,一般都是给到通用的分辨率进行设计,但是具体适配是需要代码控制的,由于网上分辨率dp的文章实在太多,对这些不了解的朋友可以去自行百度,这里主要是对U ...
- python使用redis做缓存_Python中的Redis客户端缓存(二)
Python部落(python.freelycode.com)组织翻译,禁止转载,欢迎转发. 处理失效 无效消息如何发送到被追踪的客户端取决于客户端正在使用的Redis序列化协议(RESP).早期版本 ...
- Android Picasso教程
Android Picasso is a powerful image downloading and caching library. In this tutorial, we'll be disc ...
- LruCache缓存图片+清除本地缓存
/** * * 本应用数据清除管理器 */ public class DataClearManager { /** * 获取本应用缓存大小 * @param context ...
- 分布式存储系统中的数据高效缓存方法
点击上方蓝字关注我们 分布式存储系统中的数据高效缓存方法 杨青霖, 吴桂勇, 张广艳 清华大学计算机科学与技术系,北京 100084 摘要:针对典型分布式存储系统存在的写放大.I/O路径过长.响应时延 ...
最新文章
- linux samba代码,Linux下Samba服务器源码安装及配置
- 常用SQL Server 小语法、函数 等的实例汇总
- UNILEVER STUDENT PROJECTS EVENT
- Reporting Area and Available Characteristics
- SAP CRM和Cloud for Customer中的Event handler(事件处理器)
- 内向的人很难成为群体程序员吗?
- 我是怎么进入Oracle这样的大企业的?
- 实战:基于自定义注解实现自定义框架Spring
- 【SpringMVC 笔记】SpringMVC 原理 + 入门项目(xml 配置版 vs 注解版)
- BeanFactory和FactoryBean
- for 循环 and while 循环(三)
- sqlserver express版PRIMARY 大小不能超过4G
- Perl语言入门——Perl变量简介
- java中的工作流要怎样实现_java工作流开发要怎么实现?
- 神经网络简介及简单应用
- OpenCV-直方图
- 《信贷的逻辑与常识》笔记
- 区块链会计案例_会计中区块链的特征 区块链会计应用案例
- ADX集团宣布2020年上市计划
- css中国社科,2019-2020中国CSSCI 来源期刊及扩展版目录正式公布
热门文章
- asp.net core 2.0 web api + Identity Server 4 + angular 5 可运行前后台源码
- dskinlite自适应dpi
- 开源通用爬虫框架YayCrawler-页面的抽取规则定义
- 诡异的编码和字节长度
- Service Locator Pattern in C# with Lazy Initialization(转)
- Android倒计时案例展示
- Javascript如何显示完整的大数加法结果而不是科学计数法形式
- Linux 环境下 gzip 的加解密命令
- 数字通信系统的主要性能指标
- Zend Studio 打开时提示 Failed to create the Java Virtual Machine