getAllocationByteCount
Bitmap.getAllocationByteCount() 方法获取 Bitmap 占用的字节大小
默认情况下 BitmapFactory 使用 Bitmap.Config.ARGB_8888 的存储方式来加载图片内容,而在这种存储模式下,每一个像素需要占用 4 个字节。
将同一张图片移动到drawable-hdpi下,Bitmap所占空间上涨原因:
实际上 BitmapFactory 在解析图片的过程中,会根据当前设备屏幕密度和图片所在的 drawable 目录来做一个对比,根据这个对比值进行缩放操作。
- 缩放比例 scale = 当前设备屏幕密度 / 图片所在 drawable 目录对应屏幕密度
- Bitmap 实际大小 = 宽 * scale * 高 * scale * Config 对应存储像素数
在 Android 中,各个 drawable 目录对应的屏幕密度分别为下:
加载优化
- 修改图片加载的 Config
修改占用空间少的存储方式可以快速有效降低图片占用内存。比如通过 BitmapFactory.Options 的 inPreferredConfig 选项,将存储方式设置为 Bitmap.Config.RGB_565。这种存储方式一个像素占用 2 个字节,所以最终占用内存直接减半。
ALPHA_8 代表8位Alpha位图
ARGB_4444 代表16位ARGB位图
ARGB_8888 代表32位ARGB位图
RGB_565 代表16位RGB位图【1个字节 = 8 bit 比特(位)】,一张15001000像素,使用ARGB_8888,每个像素点占用4个字节,总内存是15001000*4字节,5.7MB
- inSampleSize 参数,可以实现 Bitmap 采样压缩,这个参数的含义是宽高维度上每隔 inSampleSize 个像素进行一次采集。
当inSampleSize为2时,一个2000 * 1000的图片,将被缩小为1000 * 500,相应地,它的像素数和内存占用都被缩小为了原来的1/4
为了设置合适大小的inSampleSize,我们需要获取原始Bitmap的宽高,因此可以通过
BitmapFactory
进行获取。
BitmapFactory
提供了多个解析方法用于创建Bitmap
对象,我们应该根据图片的来源选择合适的方法。比如SD卡中的图片可以使用decodeFile
方法,网络上的图片可以使用decodeStream
方法,资源文件中的图片可以使用decodeResource
方法Android为每一种解析方法都提供了一个可选的
BitmapFactory.Options
参数,将这个参数的inJustDecodeBounds
属性设置为true
,就可以让解析方法禁止为Bitmap
分配内存,返回值也不再是一个Bitmap
对象,而是null
。但是BitmapFactory.Options
的outWidth
、outHeight
和outMimeType
属性都会被赋值。这个技巧让我们可以在加载图片之前就获取到图片的长宽值和MIME类型,从而根据情况对图片进行压缩。如下代码所示:
Bitmap复用
-
使用 Options.inBitmap 优化
实际上经过第一次显示之后,内存中已经存在了一个 Bitmap 对象。每次切换图片只是显示的内容不一样,我们可以重复利用已经占用内存的 Bitmap 空间,具体做法就是使用 Options.inBitmap 参数。
PS: Options.inMutable 置为 true,这里如果不置为 true 的话,BitmapFactory 将不会重复利用 Bitmap 内存
复用 inBitmap 之前,需要调用 canUseForInBitmap
方法来判断 reuseBitmap 是否可以被复用。这是因为 Bitmap 的复用有一定的限制:
- 在 Android 4.4 版本之前,只能重用相同大小的 Bitmap 内存区域;
- 4.4 之后可以重用任何 Bitmap 的内存区域,只要这块内存比将要分配内存的 bitmap 大就可以。
BitmapRegionDecoder 图片分片显示
在不压缩图片的前提下,不建议一次性将整张图加载到内存,而是采用分片加载的方式来显示图片部分内容,然后根据手势操作,放大缩小或者移动图片显示区域。
BitmapRegionDecoder 将图片加载到内存中,图片可以以绝对路径、文件描述符、输入流的方式传递给 BitmapRegionDecoder
Bitmap 缓存
当需要在界面上同时展示一大堆图片的时候,比如 ListView、RecyclerView 等,由于用户不断地上下滑动,某个 Bitmap 可能会被短时间内加载并销毁多次。这种情况下通过使用适当的缓存,可以有效地减缓 GC 频率保证图片加载效率,提高界面的响应速度和流畅性。
LruCache
- 图中 1 处指定 LruCache 的最大空间为 20M,当超过 20M 时,LruCache 会根据内部缓存策略将多余 Bitmap 移除。
- 图中 2 处指定了插入 Bitmap 时的大小,当我们向 LruCache 中插入数据时,LruCache 并不知道每一个对象会占用大多内存,因此需要我们手动指定,并且根据缓存数据的类型不同也会有不同的计算方式。
LruCache原理
LruCache(Least Recently Used)算法的核心思想就是最近最少使用算法。
内部维护了一个LinkHashMap
的链表,通过put数据的时候判断是否内存已经满了,如果满了,则将最近最少使用的数据给剔除掉,从而达到内存不会爆满的状态。
网友评论