1、优化Bitmap
做bitmap优化,选择合适的图片规格
- ALPHA_8 每个像素占用1byte内存
- ARGB_4444 每个像素占用2byte内存
- ARGB_8888 每个像素占用4byte内存(默认)
- RGB_565 每个像素占用2byte内存
降低采样率:BitmapFactory.Options参数inSampleSize的使用,先把options.inJustDecodeBounds设为true,只是去读取图片的大小,在拿到图片的大小之后和要显示的大小做比较,通过calculateInSampleSize()函数计算inSampleSize的具体值,得到值之后将options.inJustDecodeBounds设为false读图片资源。1
2BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
复用内存:即通过软引用(内存不够的时候才会回收掉),复用内存块,不需要再重新给这个bitmap申请一块新的内存,避免了一次内存的分配和回收,从而改善了运行效率。
2、Bitmap.recycle()会立即回收么?什么时候会回收?如果没有地方使用这个Bitmap,为什么垃圾回收不会直接回收?
- 通过源码可以了解到,加载Bitmap到内存里以后,是包含两部分内存区域的。简单的说,一部分是Java部分的,一部分是C部分的。这个Bitmap对象是由Java部分分配的,不用的时候系统就会自动回收了
- 但是那个对应的C可用的内存区域,虚拟机是不能直接回收的,这个只能调用底层的功能释放。所以需要调用recycle()方法来释放C部分的内存
- bitmap.recycle()方法用于回收该Bitmap所占用的内存,接着将bitmap置空,最后使用System.gc()调用一下系统的垃圾回收器进行回收,调用System.gc()并不能保证立即开始进行回收过程,而只是为了加快回收的到来。
3、一张Bitmap所占内存以及内存占用的计算?
Bitamp 所占内存大小 = 宽度像素 x (inTargetDensity / inDensity) x 高度像素 x (inTargetDensity / inDensity)x 一个像素所占的内存字节大小
在Bitmap里有两个获取内存占用大小的方法。
- getByteCount():API12 加入,代表存储 Bitmap 的像素需要的最少内存。
- getAllocationByteCount():API19 加入,代表在内存中为 Bitmap 分配的内存大小,代替了 getByteCount() 方法
- 在不复用 Bitmap 时,getByteCount() 和 getAllocationByteCount 返回的结果是一样的。在通过复用 Bitmap 来解码图片时,那么 getByteCount() 表示新解码图片占用内存的大 小,getAllocationByteCount() 表示被复用 Bitmap 真实占用的内存大小
4、加载本地图片,比较用decodeFileDescriptor和decodeFile的区别
- decodeFileDescriptor比decodeFile更节省内存
- 查看BitmapFactory的源码,对比一下两者的实现,可以发现decodeFile()最终是以流的方式生成bitmap
- decodeFileDescriptor的源码,可以找到native本地方法decodeFileDescriptor,通过底层生成bitmap
5、Res资源加载方式,建议采用decodeStream代替decodeResource
- 因为BitmapFactory.decodeResource 加载的图片可能会经过缩放,该缩放目前是放在 java 层做的,效率比较低,而且需要消耗java层的内存。因此,如果大量使用该接口加载图片,容易导致OOM错误,BitmapFactory.decodeStream 不会对所加载的图片进行缩放,相比之下占用内存少,效率更高。
- 这两个接口各有用处,如果对性能要求较高,则应该使用 decodeStream;如果对性能要求不高,且需要 Android 自带的图片自适应缩放功能,则可以使用 decodeResource