Android开发艺术探索 第十二章

本文探讨了Android应用中Bitmap加载可能遇到的内存溢出问题,介绍了BitmapFactory的高效加载方法,如裁剪和采样率计算。重点讲解了LruCache和DiskLruCache的缓存策略以及ImageLoader框架在图片加载、内存管理和列表优化中的应用,包括照片墙效果和解决卡顿问题的建议。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Bitmap的加载和Cache

android对单个应用内存限制,比如16M,最新版本或许可以128M,具体以最新的API为准,这就会导致Bitmap加载的时候很容易内存溢出。

Bitmap一般都采用缓存策略,避免多次加载,常用的缓存由lruCache和DiskLruCache两种,一个是内存缓存,一个是存储缓存。

列表需要加载大量子视图的时候,用户快速滑动很容易出现卡顿,如何优化是很重要的。

12.1 Bitmap的高效加载

BitmapFactory提供四类方法:decodeFile、decodeResource、decodeStream和decodeByteArray,分别支持文件、资源、输入流和字节流中加载出一个Bitmap对象,前面两个其实也是间接调用的decodeStream方法。

BitmapFactory提供裁剪的方法,可以按照一定的采样率来缩小图片大小,这样可以一定程度上降低内存一定程度上避免OOM。

获取采样率流程:

1.BitmapFactory.Options的inJusDecodeBounds参数设置为true并加载图片

2.BitmapFactory.Options中取出原始的图片宽高

3.根据采样率规则并结合目标View的大小计算采样率inSampleSize

4.BitmapFactory.Options的inJusDecodeBounds设置false,然后重新加载图片

设置inJusDecodeBounds的原因是这个加载图片是轻量级的,不会真的去全部加载,获取信息而已。

12.2 Android中的缓存策略

缓存策略主要包括缓存的添加、获取和删除,主要用到的算法是LRU,也就是近期最少使用算法。

常用的一些框架也可以参考一下,比如ImageLoader,很多网络框架本身也集成了图片框架,可以留意最新的消息。

12.2.1 LruCache

LruCache是线程安全的,内部使用的是linkedHashMap集合,使用比较简单,就是根据KEY获取和设置缓存对象就可以了,remove方法可以移除一个指定缓存对象。有兴趣可以看一下相关源码

12.2.2 DiskLruCache

DiskLruCache是磁盘缓存,他可以将缓存对象写入文件系统中。

1.DiskLruCache的创建

DiskLruCache不能直接构造,可以通过open方法来创建自身。open方法有四个参数,其中分别是:缓存的存储路径、应用的版本号、单个节点对应的数据个数和缓存的总大小。

2.DiskLruCache的缓存添加

DiskLruCache的缓存操作都是通过Editor完成的,Editor表示一个缓存对象的编辑对象,也是一样需要图片对应的KEY,然后根据KEY来获取Editor编辑对象,可以使用文件的MD5来作为KEY。在编辑完成后需要Editor去commit来提交写入操作,类似SP文件操作。

3.DiskLruCache 缓存查找

和添加流程类似,根据URL转换为KEY,根据EKY获取到snapshot对象,然后获取缓存的文件输入流,最后转换成为Bitmap对象。

12.2.3 ImageLoader的实现

ImageLoader具备以下功能:

1.图片的同步和异步加载

2.图片压缩

3.内存缓存

4.磁盘缓存

5.网络拉取

内存缓存和磁盘缓存是ImageLoader的核心,还有就是列表里面的ITEM也是需要考虑的,因为他们内部View是会复用的,需要特殊处理。

ImageLoader的实现步骤:

1.图片压缩功能的实现

主要是ImageResizer这个类实现的,具体逻辑可以参考前面讲的,或者看最新代码。

2.内存和磁盘缓存的实现

ImageLoader初始化的时候就会创建LruCache和DiskLruCache,分别来完成内存缓存和磁盘缓存的工作。磁盘缓存上限50M,取决于当前进程可以使用的内存上限,具体情况具体分析。

3.同步加载和异步加载的接口设计

同步加载:从loadBitmap中看出,工作流程主要是首先尝试从内存缓存中读取,然后是磁盘缓存,最后才是网络拉去,都是在线程中处理的,通过检查当前线程的Looper是否是主线程的Looper来判断当前线程是否是主线程,不是就会抛出异常。

异步加载:从bindBitmap看,流程基本和同步一直,区别在于图片加载成功后需要绑定到ImageView封装成一个LoaderResult对象,然后通过mMainHandler来向主线程中发送一个小希,这样就可以在主线程中给ImageView来设置图片了。

加载一般用线程池,主要是避免在列表的时候创建过多的线程,一般配置核心线程是当前设置的CPU核心数+1,最大容量为CPU核心的2倍+1,线程超时时长为10秒。

ImageLoader使用的Handler是直接采用主线程里面的Looper来构成的Handler对象,这样使得ImageLoader也可以在非主线程中构造。

为了解决View复用导致列表错位这一个问题,在给ImageView设置图片之前都会检查它的URL有没有发生改变,如果发生改变就不在设置。

12.3 ImageLoader的使用

具体使用参考开源库的最新API,这样跳过就不做陈述了。

12.3.1照片墙效果

核心代表就是mImageLoader.bindBitmap(uri,imageView,mImageVidth,mImageWidth),剩下的就交给ImageLoader来实现了。

12.3.2 优化列表的卡顿现象

不要在主线程中做耗时操作。

1.不在getView的时候执行加载图片等耗时操作

2.控制异步执行的频率,建议是等UI更新完成后再去加载,当列表处于滑动中先等待,等滑动停止了在加载图片。

3.可以开启硬件加速。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时代我西

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值