因为Android对单个应用所施加的内存限制如16mb,所以我们想办法高速加载Bitmap。
实际开发中经常用到Bitmap做缓存。比较常用的缓存策略有LruChache和DiskLruChache。
前者常被用做内存缓存,后者则是存储缓存。Lru是Least Recently Used的缩写,即最近最少使用算法,它的核心思想为:当缓存快满时,会淘汰近期最少使用的缓存目标。
Bitmap的高效加载
如何加载一个Bitmap呢,BitmapFactory提供了四个方法:decodeFile、decodeResource、decodeStream、decodeByteArray,分别用于从文件系统、资源、输入流以及字节数组中加载处一个Bitmap对象。都是Android底层实现的,对应着BitmapFactory的几个native方法。
**高效加载Bitmap核心思想就是使用Bitmap.Options方法加载所需尺寸的图片。**因为一般ImageView的尺寸都没有图片大,所以把图片整个加载进来就显得很拖沓,所以先把图片按照一定的采样率缩小,然后加载给ImageView。这会一定程度避免程序OOM,提高了加载性能。
通过Options来缩放图片,主要用到的是inSampleSize参数,即采样率。当其大于1,比如为2时,图片宽高取1/2,像素变为原来的1/4,内存也变为1/4,比如一个1024*1024像素采用ARGB8888存储格式的图片来说,其大小为1024*1024*4=4mb,缩小后大小为1mb。所以采样率的缩放比例为1/(inSampleSize^2),比如采样率为4,则缩放比例就是1/16。一般这个数自定位2的指数。
获取采样率的步骤:
(1)将BitmapFactory.Options的inJustDecodeBounds参数设置为true并加载图片
(2)从BitmapFactory.Options中取出图片的原始宽高信息,它们对应于outWidth和outHeight参数。
(3)根据采样率的规则并结合目标View的大小计算inSampleSize
(4)将BitmapFactory.Options的inJustDecodeBounds参数设置为false,然后重新加载图片。
经过上述四个步骤,加载出来的是缩放后的图片。inJustDecodeBounds设置为True时,BitmapFactory只会去解析图片的原始宽/高而不会加载它,所以这个操作时轻量级的。所以有如下代码:
通过上述的代码,我们使用就简便了,比如一个ImageView的大小为100*100,使用为:
除了用decodeResource还可以用其他三个方法来解析加载图片。
Android中的缓存策略
可以用LruChache和DiskLruChache结合实现一个优秀的ImageLoader。
LruChache
LruChache是一个缓存类、泛型类,它内部采用了一个LinkedHashMap以强引用的方式存储外界的缓存对象,其提供了get和put方法来完成缓存的获取和添加操作,当缓存满时,LruChache会移除较早使用的缓存对象,然后添加新的缓存对象。下面要弄清楚强引用、弱引用、软引用
- 强引用
直接的对象应用。
- 软引用
当一个对象只有软引用存在时,系统内存不足时,此对象会被gc回收。
- 弱引用
当一个对象只有弱引用存在时,此对象随时会被gc回收。
另外LruChache线程是安全的。下面为LruChache的初始化:
上面代码中,只需提供缓存的总容量大小并重写sizeOf即可。sizeOf的作用是计算缓存对象的大小,单位和总容量一致。上例中,总容量大小为当前进程可用内存的1/8,单位为KB,而siezOf则完成了Bitmap对象大小的计算,除1024也是将单位转化为KB,特殊情况下还要重写entryRemoved方法,在这个方法中做一些资源的回收工作。
通过get、put、remove可以得到、添加、删除一个缓存对象。
LruChacha其实已经是Android源码的一部分了。
DiskLruChache
DiskLruChache作用是实现存储设备缓存,即磁盘存储,它通过将缓存对象写入文件系统从而实现缓存效果。
DiskLruChache并不能通过构造方法来创建,而是通过open来创建自身。
第一个参数为磁盘缓存在文件系统中的存储路径,可以选择sd卡的缓存目录,第二个为应用的版本号,第三个为单个节点对应的数据的个数,一般设为1,第四个表示缓存总大小,当缓存超出这个大小后,会清楚一些缓存。
DiskLruChache的缓存添加
DiskLruChache的缓存添加操作是通过Editor完成的,Editor表示一个缓存对象的编辑对象。实例中,我们首先获取图片的Url所对应的key,然后根据key就可以通过edit()来获得Editor的对象,如果这个缓存正在被编辑则返回null,因为DiskLruChache不允许同时编辑一个缓存对象。之所以要把url转化为key是因为url中可能有特殊字符。一般用url的md5值作为key。
将图片的url转为key之后就可以获取Editor对象了,对于这个key来说如果当前不存在其他的Editor则edit()返回一个新的Editor对象,通过它可以得到一个文件输出流。open中因为设置了一个节点只能有一个数据,则下面的DISK_CHACHE_INDEX设为0就可以了
有了这个文件输出流,从网上下载这个图片就可以通过这个输出流写入到文件系统上。实现如下:
经过上面的步骤,还必须通过Editor.commit()来提交写入操作。如果写入出现异常,则可以用abort()来退回整个操作。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
大厂面经、学习笔记、源码讲义、实战项目、讲解视频**
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-y8hocR63-1710916035891)]