今天介绍一些关于Bitmap
的基础知识:bash
Bitmap
是什么drawable
文件夹Bitmap.Options
Bitmap
所占内存Bitmap
官方的说法是:Bitmap
是对位图的抽象。 形象地来讲,咱们在手机屏幕上所看到的图片就是由一个个像素点拼接而成的,每一个像素点的都是用不一样数量的二进制位来表示,而Bitmap
就是用来保存这些二进制位。app
Bitmap
占用内存分析前面咱们说到,Bitmap
的最终目的是为了在屏幕上显示图片,因此首先咱们须要了解关于屏幕密度的相关知识:ui
px
:若是咱们近距离地看手机屏幕,就能够发现它有一个个小点,每个小点就表示一个像素,咱们一般称它为px
。1920 * 1080
,也就是说它的高有1920px
,宽为1080px
,像素点总和就是1920 * 1080px
。px
为单位,而是用英寸为单位的,它和咱们平时说的米、厘米是一个概念。ppi
:英文名为pixel per inch
,中文全称为每英寸屏幕上的像素数,它决定了屏幕的质量,一般是按手机的对角线来计算的,也就是说,它等于对象线的像素个数除以对角线的长度(单位为英寸)。dp/dip
:英文名为density-independent pixel
,这是安卓特有的概念,它和px
的做用相同,都是用来表示长度。可是它和硬件屏幕无关,若是须要转换为px
,那么1dp
在屏幕上最终会显示为(ppi / 160)
个px
。dpi
:英文名为dot per inch
,中文全称为每英寸图片上点的个数,它决定了图片的质量,好比dpi
为320
,那么最终在手机上一张320 * 320
的图片就会用320 * 320 * (dpi / 160)
个像素点来表示。在Android
中,经过DisplayMetrics
能够得到上述的信息:spa
public static void logDensityInfo(Activity activity) {
DisplayMetrics displayMetrics = new DisplayMetrics();
//将信息保存到displayMetrics中.
activity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
//1.x轴和y轴的dpi.
Log.d("logDensityInfo", "ydpi=" + displayMetrics.ydpi);
Log.d("logDensityInfo", "xdpi=" + displayMetrics.xdpi);
//2.x轴和y轴的像素个数.
Log.d("logDensityInfo", "heightPixels=" + displayMetrics.heightPixels);
Log.d("logDensityInfo", "widthPixels=" + displayMetrics.widthPixels);
//3.dpi
Log.d("logDensityInfo", "densityDpi=" + displayMetrics.densityDpi);
//4.dpi/160.
Log.d("logDensityInfo", "density=" + displayMetrics.density);
//5.一般状况下和density相同.
Log.d("logDensityInfo", "scaledDensity=" + displayMetrics.scaledDensity);
}
复制代码
在个人手机上,最终的结果是: code
dpi
相关的值是怎么得到的:
public void setToDefaults() {
density = DENSITY_DEVICE / (float) DENSITY_DEFAULT;
densityDpi = DENSITY_DEVICE;
scaledDensity = density;
xdpi = DENSITY_DEVICE;
ydpi = DENSITY_DEVICE;
}
复制代码
其中DENSITY_DEFAULT
为160
,而DENSITY_DEVICE
则是经过下面方式获得的:对象
private static int getDeviceDensity() {
return SystemProperties.getInt("qemu.sf.lcd_density", SystemProperties.getInt("ro.sf.lcd_density", DENSITY_DEFAULT));
}
复制代码
drawable
文件夹内的图片提及dpi
,天然就会想到res
文件夹下的drawable-?
文件夹,咱们在平时开发中会发现,若是将同一大小的图片,放在不一样的drawable
文件夹下,最终在屏幕上展示的大小是不同的。 这实际上是Android
在读取资源的时候,会根据文件夹的不一样,给每一个文件夹定义一个叫作density
的属性,根据最终找到的资源所在的文件夹位置,会有如下几种状况:图片
dpi
文件夹:不进行缩放。drawable-nodpi
其它的dpi
文件夹:那么最终的长度变为(原始长度 / 所在文件夹density) * 匹配文件夹density
drawable-nodpi
:不进行缩放。而每一个ARBG
位的二进制个数相乘,就是图片所占内存的大小,对应的density
以下:ip
drawable-nodpi
:不缩放drawable-ldpi
:0.75
drawable
:1
drawable-mdpi
:1
drawable-hdpi
:1.5
drawable-xhdpi
:2
drawable-xxhdpi
:3
drawable-xxhdpi
:4
若是某个资源存在于上面的多个文件夹下,它的匹配优先级以下:内存
dpi
匹配的dpi
文件夹dpi
高的dpi
文件夹drawable-nodpi
dpi
低,但大于等于1
的dpi
文件夹drawable
drawable-ldpi
Bitmap.Config
这是一个枚举类型,它用来描述每一个像素是如何被保存的,它会影响图片的质量并决定可否表示透明/半透明颜色。资源
ALPHA_8
:每一个像素点仅表示alpha
的值,它不会存储任何颜色信息,占8位
。RGB_565
:每一个像素用5位R/6位G/5位G
来表示,占16位
。ARGB_8888
:每一个像素分别用8位
存储ARGB
,占32位
。ARGB_4444
:和8888
相似,只不过对于每一个通道是使用4位
表示,所以它的图片质量比较低,已经不推荐使用了。已经介绍完所须要掌握的基础知识,总结下来,Bitmap
所占内存大小其实由两个因素决定:
ARGB
所占位宽第一点的影响因素有:原始图片的宽高、手机内置的dpi
、图片所放位置。 第二点的影响因素有:Bitmap
所对应的Bitmap.Config
配置。
下面咱们几个例子,验证前面说的三种状况:
720 * 1280
,它所匹配到的文件夹为drawable-xhdpi
,咱们先将一个原始大小为48 * 48
的图片方在drawable-xhdpi
文件夹中,并配置Option
为Bitmap.Config.RGB_565
:private void logWrapperImageView() {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.drawable_test, options);
Log.d("logWrapperImageView", "width=" + bitmap.getWidth() + ",height=" + bitmap.getHeight() + ",size=" + bitmap.getByteCount());
}
复制代码
这种状况下最终的结果为,虽然咱们指出了须要用RGB_565
,可是系统每一个像素仍是只用了一位:
width=48,height=48,size=2304 //RGB_565
width=48,height=48,size=9216 //ARGB_8888
width=48,height=48,size=2304 //ALPHA_8
复制代码
1080 * 1920
,它所匹配到的文件夹为drawable-xxhdpi
,咱们先将一个原始大小为48 * 48
的图片方在drawable-xxhdpi
文件夹中,并配置Option
为Bitmap.Config.RGB_565
,运行和上面同样的程序,获得的结果为:width=48,height=48,size=2304 //RGB_565
复制代码
接着改变它的Options
:
width=48,height=48,size=9216 //ARGB_8888
width=48,height=48,size=2304 //ALPHA_8
复制代码
drawable-nodpi
的文件夹中720 * 1280
,把图片放在drawable-xxhdpi
文件夹中:width=32,height=32,size=4096 //RGB_565
复制代码
改变它的Options
:
width=32,height=32,size=4096 //ALPHA_8
width=32,height=32,size=4096 //ARGB_8888
复制代码
1080 * 1960
,把图片放在drawable-xhdpi
文件夹中:width=72,height=72,size=20736
复制代码
改变它的Options
width=72,height=72,size=20736 //ALPHA_8
width=72,height=72,size=20736 //ARGB_8888
复制代码
drawable-nodpi
文件夹中720 * 1280
:width=48,height=48,size=2304 //RGB_565
width=48,height=48,size=9216 //ARGB_8888
width=48,height=48,size=2304 //ALPHA_8
复制代码
1080 * 1960
:width=48,height=48,size=2304 //RGB_565
width=48,height=48,size=9216 //ARGB_8888
width=48,height=48,size=2304 //ALPHA_8
复制代码
从上面的例子中,总结出几点:
dpi
文件夹,和放在drawable-nodpi
文件夹是相同的。RGB_565
时,实际占用的是一个字节。Options
,都是采用占用4字节
的方式。dpi
文件夹下和drawable-nodpi
文件夹下时,长宽不进行缩放。匹配文件夹density/所在文件夹density
,以上面3.5.2
的720 * 1280
手机为例,原始的图片的长宽为48
,其匹配文件夹的density
为2
,所在文件夹的density
为3
,因此缩放倍数为2/3
,所以,最后的长宽为32
。Bitmap
所占内存大小就等于它的长宽乘以每一个像素所占位数。