Bitmap基础知识

(一)

Bitmap所占用的内存 = 图片长度 x 图片宽度 x 一个像素点占用的字节数

A代表透明度;R代表红色;G代表绿色;B代表蓝色
ALPHA_8        表示8位 Alpha位图,即A=8,一个像素点占用一个字节,它没有颜色,只有透明度
ARGB_4444    表示16位 ARGB位图,即A=4, R=4, G=4, B=4,一个像素点占 4+4+4+4=16位,2个字节
ARGB_8888    表示32位 ARGB位图,即A=8, R=8, G=8, B=8, 一个像素点占8+8+8+8=32位,4个字节

RGB_565        表示16位 RGB位图,即R=5, G=6, B=5,它没有透明度,一个像素点占用5+6+5=16位,2个字节

(二)

BitmapFactory.Options

inScaled             设置 Bitmap 是否可以被缩放,默认值是 true,表示可以被缩放
inSampleSize     < 1 : 当做1处理
  > 1 : 按照比例(1 / inSampleSize)缩小 bitmap的宽和高、降低分辨率
inDensity          表示这个 bitmap 的像素密度(对应的是 DisplayMetrics中的 densityDpi,不是 density)
inTargetDensity         表示要被画出来时的目标像素密度(对应的是 DisplayMetrics中的 densityDpi,不是 density)
inScreenDensity    表示实际设备的像素密度(对应的是 DisplayMetrics中的 densityDpi,不是 density)
inJustDecodeBounds  true : 解码的时候不会反回bitmap,只会反回这个bitmap的尺寸
inPreferredConfig     设置彩色模式,默认值为 ARGB_8888,一个像素点占 4个字节
一般对透明度不做要求的话,一般采用 RGB_565
inPremultiplied         和透明度通道有关,true,反回的 bitmap 的颜色通道上回预先附加上透明度通道
inDither                    和抖动解码有关,默认false,表示不采用抖动解码
inPurgeable和inputShareable true,     前者表示空间不够是否可以被释放,后者表示是否可以共享引用,两个值在Android 5.0后被弃用

inPreferQualityOverSpeed         表示在解码时图片有更高的品质,仅用于JPEG格式,如果设置为true,图片会有更高的品质,但是解码速度会很慢

outWidth 和 outHeight             表示这个Bitmap的宽和高,一般和 inJustDecodeBounds 一起使用来获得 Bitmap的宽高,但不加载到内存

(三)

PNG 与 JPEG 的比较:
(1) 尽量减少PNG图片的大小是Android里面很重要的一条规范。相比于JPEG,PNG能够提供更加清晰无损的图片,但是PNG格式的图片会更大,占用更多的磁盘空间
(2) 预缩放图片  
对bitmap做缩放,提示显示性能,避免分配不必要的内存。Android提供了现成的 bitmap缩放的 API,叫做createScaledBitmap(),这个方法能够执行的前提是,原图片需要事先加载到内存中,如果原图过大,很可能导致OOM。下面介绍其他几种缩放图片的方式:
① inSampleSize 能够等比的缩放显示图片,同时还避免了需要先把原图加载进内存的缺点
② 可以使用 inScaled、inDensity、inTargetDensity的属性来对解码图片进行处理,如下所示:
mBitmapOptions.inScaled = true;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity = dstWidth;
mCurrentBitmap = BitmapFactory.decodeResources(getResources(), mImageIDs, mBitmapOptions);
③ 使用 inJustDecodeBounds,可以事先获取到图片的大小而不至于占用什么内存
mBitmapOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(fileName, mBitmapOptions);
srcWidth = mBitmapOptions.outWidth;

srcHeight = mBitmapOptions.outHeight;

(3) 重复使用bitmaps
使用inBitmap属性可以告知 Bitmap解码器去尝试使用以及存在的内存区域,新解码的 bitmap会尝试去使用之前那张 bitmap
在 heap中所占据的 pixel data内存区域,利用这种特性,即使是上千张的图片,也只会仅仅只需要占用屏幕能够显示的图片数量的内存大小。
mBitmapOptions.inBitmap = mCurrentBitmap;
mCurrentBitmap = BitmapFactory.decodeFile(fileName, mBitmapOptions);
使用inBitmap需要注意:
① SDK 11 -> 18之间,重用的 bitmap 大小必须是一致的,例如给inBitmap赋值的图片大小为100-100,那么新申请的bitmap必须也为100-100才能够被重用
   SDK 19开始,新申请的bitmap大小必须小于或者等于已经赋值郭的bitmap 大小
② 新申请的bitmap与旧的bitmap必须有相同的解码格式
   不同的编码方式占用内存时不同的。常见的 png、jpeg、webp等格式的图片在设置到UI上之前需要经过解码的过程,而解码时可以选择不同的解码率,
   不同的解码率对内存的占用是有很大差别的。Android为图片提供了4种解码格式,Android默认是使用argb8888格式,还有argb4444,alpha8及rgb565
   大图和小图可以采用不同的解码率:
mBitmapOptions = new BitmapFactory.Options();
mBitmapOptions.inPreferredConfig = Bitmap.Config.RGB_565;
BitmapFactory.decodeResource(getResources(), R.drawable.firstBitmap, mBitmapOptions);
 一张图片在内存中占用多大空间主要受图片本身大小(分辨率)、解码方式、还有就是设备像素密度这三个因素影响(像素密度是由设备定的)    
Bitmap 对象在不适用时,应该先调用 recycle()释放内存,然后才置空(加载bitmap对象的内存空间,一部分是java的,一部分是c的(因为Bitmap分配的底层是通过jni调用的,BitMap底层是skia图形库,skia图形库是c实现的,通过jni的方法在java层进行封装)。这个recycle()函数就是针对c部分的内存释放。

原则:
① 需要透明度的图片使用 PNG格式,不需要的一律使用JPG格式,使用JPG格式的图片在保证质量的前提下进行压缩
   ( JPG格式会损失透明度 )
② 尽量不要使用原图,在保证质量的前提下压缩
③ 在Android 5.0版本 google加入矢量图的支持 Vector Asset,矢量图使用于简单的图标,不适用于复杂的图片。矢量图主要解决不同分辨率下缩放导致图标不清晰,使用矢量图只需要一个文件,不再需要不同分辨率版本的图片
注意:① 矢量图适用于简单的图标 ② 如果要兼容低于 5.0版本,需要引入 support包
④ 使用 Webp图片格式,可以获得更大的压缩率,在 Android中使用注意注意低版本兼容问题。对 Android来说,4.2.1以上版本完全支
持WebP,4.0 到 4.2.1版本只支持不透明的 WebP,更低版本的不支持 WebP

你可能感兴趣的:(Android)