欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

第十二章 Bitmap 的加载和 Cache

程序员文章站 2022-07-14 20:10:37
...

Bitmap 的高效加载

  1. 由于Bitmap的特殊性以及Android 对单个应用所施加的内存限制,比如16MB,这导致加载 Bitmap 的时候很容易出现内存溢出。
  2. 加载图片:BitmapFactory 类提供了四类方法,decodeFile、decodeResource、decodeStream、decodeByteArray,分别用于支持从文件系统、资源、输入流以及字节数组中加载出一个Bitmap 对象,decodeFile、decodeResource间接调用了decodeStream,这四类方法最终是在Android的底层实现的,对应着BitmapFactory的几个native方法
    3. 如何高效地加载图片?
    采用BitmapFactory.Options来加载所需尺寸的图片,假设通过imageView来显示图片,很多时候ImageView并没有图片的原始尺寸那么大,整张图片加载进来再设置给ImageView显然没必要,通过BitmapFactory.Options就可以按一定的采样率来加载缩小后的图片,将缩小后的图片在ImageView中显示,这样就会降低内存占用从而在一定程度上避免OOM,提高了Bitmap加载时的性能。
  3. 通过 BitmapFactory.Options来缩放图片,主要是用到了inSampleSize参数,即采样率。当 inSampleSize 为1时,采样后的图片和原始图片大小相同;当 inSampleSize 为2时,采样后的图片其宽高均为原图大小的1/2,像素数为原图大小的1/4。
    如何获取采样率?
    (1) 将BitmapFactory.OptionsinJustDecodeBounds参数设为true并加载图片
    (2) 从BitmapFactory.Options中取出原始宽高信息,对应于outWidth、outHeight
    (3) 根据采样率的规则并结合目标view的所需大小计算出采样率inSampleSize
    (4) 将 BitmapFactory.OptionsinJustDecodeBounds设为 false 然后重新加载图片
    inJustDecodeBounds参数 当此参数为 true 时,BitmapFactory只会解析图片的宽高信息,并不会真正地加载图片,该操作是轻量级的。此时BitmapFactory获得的图片宽高信息和图片的位置以及程序运行的设备有关,比如一张图片放在不同的 drawable 目录下,或者程序运行在不同屏幕密度的设备上,都会导致 BitmapFactory 获取到不同的结果,原因是和 Android 的资源加载机制有关。
        BitmapFactory.decodeResource();
        BitmapFactory.decodeFile();
        BitmapFactory.decodeStream();
        BitmapFactory.decodeByteArray();

以上四个方法都是支持采样率加载的,处理方式也是类似的。decodeStream()有些特殊,需要获取流的文件描述符FileDescriptor,通过BitmapFactory.decodeFileDescriptor加载。

Android 中的缓存策略

1. 如何避免过多的流量消耗呢?
缓存。当程序第一次从网上加载图片后,就将其缓存到设备上,为了提高用户体验,往往还会想内存中缓存一份。当应用打算从网络上请求一张图片时,程序会首先从内存中获取,如果内存中没有就从设备中获取,如果设备中没有,就从网络上下载。该缓存策略不仅适用于图片,也适用于其他文件类型。
2. 常用缓存算法:LRU。LRU是近期最少使用算法,核心思想:当缓存满时,会优先淘汰那些近期最少使用的缓存对象。采用LRU算法的缓存有两种:LruCacheDiskLruCache
LruCache
内部采用一个LinkedHashMap以强引用的方式存储外界的缓存对象。当缓存满的时候,LruCache 会移除较早使用的缓存对象,然后再添加对象。LruCache 是线程安全的。
强引用:直接的对象引用
软引用:当一个对象只有软引用存在时,系统内存不足时此对象会被 gc 回收
弱引用:当一个对象只有弱引用存在时,此对象会随时被gc回收
DiskLruCache
磁盘缓存。

ImageLoader 的实现

一个优秀的ImageLoader应该具备如下功能:
图片的同步加载;图片的异步加载;图片压缩;内存缓存;磁盘缓存;网络拉取
图片的同步加载:以同步的方式向调用者提供所加载的图片,该图片可能是从内存、磁盘和网络中拉取的。
图片的异步加载:调用者无需在单独的线程中以同步的方式获取图片,此时ImageLoader需要自己在线程中加载图片并将图片设置给所需的ImageView
图片压缩:降低OOM概率的有效手段
内存缓存、磁盘缓存:极大提高程序效率,有效降低用户流量。
列表错位:对于ListView、GridView等,由于 itemView 的复用导致的列表错位。

优化列表的卡顿现象

不要在主线程做太多的耗时操作即可提高滑动的流畅度。
1. 不要在getView中执行耗时操作。
2. 控制异步任务的执行频率。
如果用户可以频繁上下滑动,就会一瞬间产生上百个异步任务,这些任务会造成线程池的拥堵并随即带来大量的UI更新操作,造成一定程度的卡顿?
解决:可以考虑在列表滑动的时候停止加载图片,开启硬件加速。

相关标签: 第十二章