Bitmap的加载跟缓存

首先来讲述如何有效的加载一个Bitmap,由于Bitmap的特殊性以及Android对单个应用所施加的内存限制,比如说16MB,这导致加载Bitmap的时候很容易出现内存溢出。

1.Bitmap在Android中指的是一张图片,可以是png格式也可以是jpg等其他常见的图片格式。BitmapFactory类提供了四类方法:decodeFile、decodeResource、decodeStream和decodeByteArray,分别用于支持从文件系统、资源、输入流以及字节数组中加载一个Bitmap对象,其中decodeFile和decodeResource又间接调用了decodeStream方法,这四类方法最终是在Android的底层实现的,对应着BitmapFactory类的几个native方法。

高效加载Bitmap的核心思想就是采用BitmapFactory.Options来加载所需尺寸的图片。这里假设通过ImageView来显示图片,很多时候ImageView并没有图片的原始尺寸那么大,这时候把整个图片加载进来后再设给ImageView,这显然是没有必要的,因为ImageView并没有办法显示原始的图片。通过BitmapFactory.Options就可以按一定的采样率来加载缩小后的图片,将缩小后的图片在ImageView中显示,这样就会降低内存占用从而在一定程度上避免OOM,提高了Bitmap加载时的性能。BitmapFactory提供的加载图片的四类方法都支持BitmapFactory.Options参数,通过它们就可以很方便地对一个图片进行采样缩放。

通过BitmapFactory.Options来缩放图片,主要是用到了它的inSampleSize参数,即采样率。比如inSampleSize为1,采样后的图片大小为图片的原始大小,为2时,采样后的图片其宽/高约为原图大小的1/2,而像素为原图1/4,其占有内存大小也为原图的1/4.

获取采样率流程很简单:

(1)将BitmapFactory.Options的inJustDecodeBounds参数设为true并加载图片

(2)从BitmapFactory.Options中取出图片的原始宽高信息,它们对应于outWidth和outHeight参数

(3)根据采样率的规则并结合目标View的所需大小计算出采样率inSampleSize

(4)将BitmapFactory.Options的inJustDecodeBounds参数设为false,然后重新加载图片

2.Android中的缓存策略

缓存策略在Android中有着广泛的使用场景,尤其是图片加载这个场景下,缓存策略就变得更为重要。考虑一种场景,要下载一批图片,在PC环境下就很简单,直接把所有的图片下载到本地再显示即可,但是在移动设备上就不一样了,不管是Android还是IOS设备,流量对于用户来说都是一种宝贵的资源,由于流量是收费的,所以在应用开发中并不能过多地消耗用户的流量,否则这个应用肯定不能被用户所接受。

如何避免过多的流量消耗,利用缓存。当程序第一次从网络家族图片后,就将其缓存到存储设备上,这样下次使用这张图片就不用再从网络上获取了,这样就为了用户节省了流量。很多时候为了提高应用的用户体验,往往还会把图片在内存中再缓存一份,这样当应用打算从网络上请求一张图片时,程序会首先从内存中去获取,如果内存中没有那就从存储设备中获取,如果存储设备中也没有,那就从网络上下载这张图片。因为从内存中加载图片比从存储设备中加载图片要快,所有这样既提高了程序的效率又为用户节约了不必要的流量开销。上述的缓存策略不仅仅适用于图片,也适用于其他文件。

说到缓存策略,一般的缓存策略包含添加、获取和删除,为什么要删除呢?因为无论是内存还是存储设备都是有容量的限制的,因此在使用缓存时总要为缓存设定一个最大容量。如果容量满了,但是程序还会继续添加缓存,这就需要删除一些旧的缓存并添加新的缓存,怎么定义缓存新旧呢?不同的缓存策略就对应着不同的缓存算法,比如可以简单的根据文件的最后修改时间来定义缓存的新旧,当满的时候就将最后修改时间比较早的缓存删除,这就是一种缓存的算法。

目前比较常用的一种算法是LRU(Least  Recently  Used),LRU是近期最少使用算法,核心思想是当缓存满了,会优先淘汰那些近期最少使用的缓存对象。采用LRU算法的缓存有两种:LruCache和DiskLruCache,LruCache用于实现内存缓存,而DiskLruCache则充当了存储设备缓存,

2.1LruCache

LruCache是一个泛型类,它内部采用一个LinkedHashMap以强引用的方法存储外界的缓存对象,其提供了get和put方法来完成缓存的获取和添加。当缓存满了,LruCache会移除较早使用的缓存对象,然后添加新的缓存对象。

强引用:直接的对象引用

软引用:当一个对象只有软引用存在时,系统内存不足时此对象会被gc回收。

弱引用:当一个对象只有弱引用存在时,次对象会随时被gc回收。

另外LruCache是线程安全的。

LruCache的获取,添加、删除对应的方法LruCache.get(key)、LruCache.put(key,bitmap)、LruCache.remove(key)

2.2DiskLruCache

DiskLruCache用于实现存储设备缓存,即磁盘缓存,它通过将缓存对象写入文件系统从而实现缓存效果。

DiskLruCache并不能通过构造方法来创建,它提供了open方法用于创建open(File Directory,int appVersion,int valueCount,long maxSize)

open方法有四个参数,第一个参数表示磁盘缓存在文件系统中的存储路径。缓存路径可以选择适sd卡上的缓存目录,具体是指/sdcard/Android/data/package_name/cacha目录,当应用被卸载后,此目录会一并被删除。当然也可以选择sd卡上其它指定目录,具体根据需求灵活设定。如果应用卸载后希望删除换文件,那么久选择sd卡上的缓存目录,如果希望保留缓存数据就应该选择sd卡上的其它目录。

第二个参数表示应用的版本号,一般设为1即可。当版本号发生改变时,会清空之前所有的缓存文件,在实际开发中作用不大。

第三个参数表示单个节点所对应的数据的个数,一般设为1即可。

第四个参数表示缓存的总大小,超过设定的值,就会清除一些缓存来保证总大小不大于这个值。

DiskLruCache的缓存添加是通过Editor完成的,Editor表示一个缓存对象的编辑对象,这里仍然以图片为例,首先需要获取图片url所对应的key,(把图片url转为key是因为图片url可能有特殊字符,一般采用url的md5值作为key)。然后根据key就可以通过edit()来获取Editor对象(如果这个缓存正在被编辑,那么edit()会返回null,即DiskLruCache不允许同时编辑一个缓存对象),通过它就可以得到一个文件输出流。当从网络下载图片时,图片就可以通过这个文件流写入到文件系统上。最后还必须通过Editor对的commit() 来提交写入操作,如果下载图片有异常,可以通过Editor的abort()来回退整个操作。

DiskLruCache的缓存查找过程也需要将url转换为key,然后通过DiskLruCache的get方法得到一个Snapshot对象,接着再通过Snapshot对象即可得到缓存的文件输出流,有了文件输出流,自如就可以得到BItmap对象,但是为了避免加载图片导致OOM,一般不建议直接加载原图。BitmapFactory.Options对象加载缩放图,但是那种方法对FileInputStream的缩放存在问题,两次decodeStream的调用影响文件流的文职属性,导致第二次得到的是null。解决这个问题,可以通过文件流来得到它所对应的文件描述,然后通过BitmapFactory.decodeFileDescriptor方法来加载一张缩放后的图片。还提供了remove、delete等方法用于磁盘缓存的删除操作。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值