本篇记录一下Android开发艺术探索的Bitmap的相关知识。
概述
本章主要介绍了Bitmap的高效加载,Android中的常用缓存策略包括LruCache和DiskLruCache,对于列表卡顿的优化。
Bitmap的高效加载
首先看一下Bitmap的加载,使用BitmapFactory提供的4类方法:decodeFile、decodeResource、decodeStream、和decodeByteArray,分别用于支持从文件系统,资源,输入流以及字节数组中加载出一个Bitmap对象,其中decodeFile和decodeResource又间接调用了decodeStream方法。
如何高效的加载图片?可以采用BitmapFactory.Options来加载所需尺寸的图片。即将需要加载的图片缩放后再加载进来。主要用到了BitmapFactory.Options的inSampleSize参数:采样率。当inSampleSize为1时,图片为原来大小,而当它大于1时,比如为2的时候,采样后的图片宽高都是原来的1/2,而图片大小则变成原来的1/4。
也即是说采样率必须大于1才会有效果,而且采样率同时作用于宽高,采样后的图片大小为之前的1/4,官方建议采样率大小为2的指数形式。
获取采样率的流程如下:
- 将BitmapFactory.Options的inJustDecodeBounds设置为true并加载图片。
- 从BitmapFactory.Options中取出图片的原始宽高信息,它们对应于outWidth和outHeight参数。
- 计算出所需的采样率inSampleSize
- 将BitmapFactory.Options的inJustDecodeBounds设置为false并重新加载图片
说明一下inJustDecodeBounds这个参数,当它设置为true的时候,BitmapFactory只会解析图片的原始宽高信息,并不会去真正加载图片,而这个宽高信息和图片的位置和运行设备有关。比如一张图片放在不同drawable目录下或者在不同的设备上,获取到的结果都有可能不同,这和Android的资源加载机制有关。
上述流程的代码如下:
|
|
Android中的缓存策略
缓存策略主要包含缓存的添加、获取和删除这三类操作。目前常用的一种缓存算法是LRU(Latest Recently Used),LRU是近期最少使用算法,就是说当缓存满时,会优先淘汰那些近期最少使用的缓存对象。采用LRU的缓存有两种:LruCache和DiskLruCache,LruCache用于实现内存缓存,而DiskLruCache则是存储设备缓存,者两者的完美结合就可以很方便的实现一个ImageLoader。
LruCache
LruCache是Android3.1提供的一个缓存类,建议使用support_v4兼容包中的。
LruCache是一个泛型类,内部采用一个LinkedHashMap以强引用的方式存储外界的缓存对象,它提供了get和put来完成缓存的获取和添加操作,当缓存满时,LruCache会移除焦躁使用的缓存对象,然后再添加新的缓存对象。
- 强引用: 直接的对象引用
- 软引用: 当一个对象只有软引用存在时,系统内存不足时,次对象会被回收。
- 弱引用: 当一个对象只有弱引用时,此对象随时会被gc回收。
LruCache是线程安全的,用图片缓存来举例说明LruCache的初始化过程:
|
|
上面的代码中,只需要提供缓存总容量大小并重写sizeOf方法即可。sizeOf的作用是计算缓存对象的大小,这里大小的单位需要和总容量的单位一致。上述代码中,总容量大小为当前进程的可用内存的1/8,单位为KB,而sizeOf方法则完成了Bitmap对象的大小计算。除以1024就是为了将其单位转换为KB,和总容量大小的单位一致。
某些特殊情况下,还需要重写LruCache的entryRemove方法,LruCache移除旧缓存时会调用entryRemove方法,可以在entryRemove中完成一些资源回收工作。
从LruCache中获取一个缓存对象:
|
|
向LruCache中添加一个缓存对象:
|
|
LruCache还支持删除操作,通过remove方法即可删除一个指定的缓存对象。
书中对于LruCache的实现并没有做详细的介绍,我自己分析了一下源码的实现LruCache的实现原理分析