内容简介: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 懒加载(与预加载)组件
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
民事诉讼程序研究
乔罗威茨 / 吴泽勇 / 2008-6 / 40.00元
《民事诉讼程序研究》共分为诉讼程式;扩散利益、分散利益和集体利益的保护;程式样式;当事人与法官;对判決的救济;程式改革。主要內容包括:民事诉讼;英美民事诉讼程式在20世纪的若干发展;论民事诉讼法的本质和目的等。一起来看看 《民事诉讼程序研究》 这本书的介绍吧!