内容简介:Android 中如何高效地加载 Bitmap 是一个很重要也很容易被我们忽视的问题。DiskLruCache 用于实现存储设备缓存,即磁盘缓存,它通过将缓存对象写入文件系统从而实现缓存的效果。项目地址:一个优秀的图片加载器应具备:
Android 中如何高效地加载 Bitmap 是一个很重要也很容易被我们忽视的问题。
Bitmap 的高效加载
-
BitmapFactory 类提供了:
decodeFile、decodeResource、decodeStream、decodeByteArray以及decodeFileDescriptor等几类方法来加载一个 Bitmap 对象。 -
高效加载 Bitmap 的核心思想就是设置
BitmapFactory.Options的inSampleSize采样率属性来加载所需尺寸的图片。inSampleSize = 1 时加载原图,inSampleSize = 2 时加载的像素为原图的 1/4,以此类推。官方推荐设置 inSampleSize 的值为 2 的指数。
-
获取采样率的流程:
-
将
BitmapFactory.Options的inJustDecodeBounds参数设为true并加载图片。 -
从
BitmapFactory.Options中取出图片的原始宽高信息,它们对应于outWidth和outHeight。 -
根据采样率的规则并结合目标 View 的所需大小计算出采样率
inSampleSize。 -
将
BitmapFactory.Options的inJustDecodeBounds参数设为false然后重新加载图片。示例代码public Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { // 设置 inJustDecodeBounds = true 时 BitmapFactory 只会解析图片的原始宽高等信息。 // 并不会真正地去加载图片 final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resId, options); // 计算采样率 options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // 重新加载图片 options.inJustDecodeBounds = false; return BitmapFactory.decodeResource(res, resId, options); } public int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { if (reqWidth == 0 || reqHeight == 0) { return 1; } // 图片的原始宽高信息 final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) { inSampleSize *= 2; } } return inSampleSize; }
-
将
Android 中的缓存策略
- 缓存策略并没有统一的标准,一般来说缓存策略主要包含缓存的添加、获取和删除这三类操作。
- 常用的缓存算法是 LRU (Least Recently Used),翻译为:近期最少使用算法。它的核心思想是当缓存满时,会优先淘汰那些近期最少使用的缓存对象。
- Android 中常见的 LRU 算法缓存有两种: LruCache (内存缓存) 和 DiskLruCache (存储设备缓存),一般情况下会将两者结合使用。
LruCache
-
LruCache 是一个泛型类,内部采用一个
LinkedHashMap<K, V>以强引用的方式存储外界的缓存对象,提供了get和put等操作方法,当存储满时,会移除较早使用的缓存对象,再添加新的缓存对象。此外,LruCache 是线程安全的。三种引用的区别:
- 强引用 :直接的对象引用
- 软引用 :当一个对象只有软引用存在时,系统内存不足时此对象会被 gc 回收
- 弱引用 :当一个对象只有弱引用存在时,此对象会随时被 gc 回收
-
LruCache 典型示例代码:
// 获取当前可用的最大内存 int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); // KB // 设置缓存大小 int cacheSize = maxMemory / 8; LruCache<String, Bitmap> lruCache = new LruCache<String, Bitmap>(cacheSize) { @Override protected int sizeOf(String key, Bitmap value) { // 重写此方法计算缓存对象的大小 return value.getRowBytes() * value.getHeight() / 1024; } }; // 添加缓存 lruCache.put("liyu", bitmap); // 获取缓存 Bitmap bitmap = lruCache.get("liyu");
DiskLruCache
DiskLruCache 用于实现存储设备缓存,即磁盘缓存,它通过将缓存对象写入文件系统从而实现缓存的效果。项目地址: https://github.com/JakeWharton/DiskLruCache
-
DiskLruCache 的创建
/** * @param directory 缓存路径 * @param appVersion 一般为 1,当版本号变更时,会清空缓存文件 * @param valueCount 单个节点所对应的数据个数,一般为 1 * @param maxSize 缓存总大小,超过的话会清除一些缓存 */ public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)
-
DiskLruCache 的缓存添加
String key = hashKeyFormUrl(url); // url 转换下防止特殊字符影响 DiskLruCache.Editor editor = mDiskLruCache.edit(key); if (editor != null) { OutputStream outputStream = editor.newOutputStream(DISK_CACHE_INDEX); // DISK_CACHE_INDEX 为 0,因为设置的一个节点只有一个数据 if (downloadUrlToStream(url, outputStream)) { //下载 editor.commit(); // 下载成功提交缓存 } else { editor.abort(); // 出现异常则取消缓存 } mDiskLruCache.flush(); // 强制缓冲文件保存到文件系统 } -
DiskLruCache 的缓存查找
Bitmap bitmap = null; String key = hashKeyFormUrl(url); // url 转换下防止特殊字符影响 DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key); // 获取缓存快照 if (snapShot != null) { FileInputStream fileInputStream = (FileInputStream)snapShot.getInputStream(DISK_CACHE_INDEX); // DISK_CACHE_INDEX 为 0,因为设置的一个节点只有一个数据 FileDescriptor fileDescriptor = fileInputStream.getFD(); // 解决 decodeStream 缩放 bitmap 第二次为 null 的问题 bitmap = mImageResizer.decodeSampledBitmapFromFileDescriptor(fileDescriptor, reqWidth, reqHeight); // 缩放图片 if (bitmap != null) { addBitmapToMemoryCache(key, bitmap); // 添加到内存缓存,方便下次快速获取 } }
ImageLoader 的实现
一个优秀的图片加载器应具备:
- 图片的同步加载
- 图片的异步加载
- 图片压缩
- 内存缓存
- 磁盘缓存
- 网络拉取
完整的 ImageLoader 示例可以参考 源码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 介绍同步加载、异步加载、延迟加载[原创]
- .net加载失败的程序集重新加载
- 虚拟机类加载机制:类加载时机
- 探秘类加载器和类加载机制
- hibernate中加载策略+批加载+懒加载异常【原创】
- [译] React 16.6 懒加载(与预加载)组件
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
RESTful Web Services Cookbook
Subbu Allamaraju / Yahoo Press / 2010-3-11 / USD 39.99
While the REST design philosophy has captured the imagination of web and enterprise developers alike, using this approach to develop real web services is no picnic. This cookbook includes more than 10......一起来看看 《RESTful Web Services Cookbook》 这本书的介绍吧!