图片文件在不同文件夹下的差异
将同一张图片放在不同分辨率的文件夹下会有什么差异呢?
首先我们要先来了解一下手机屏幕密度的概念。手机屏幕密度可通过如下代码获取:
float xdpi = getResources().getDisplayMetrics().xdpi;
float ydpi = getResources().getDisplayMetrics().ydpi;
其中xdpi表示屏幕宽度的dpi值,ydpi表示屏幕高度的dpi值,通常这两个值都是相等或极其接近的,如两个值都等于403,那么403又表示什么呢?我们参考下表即可知道:
dpi范围 | 密度 |
---|---|
0dpi~120dpi | ldpi |
120dpi~160dpi | mdpi |
160dpi~240dpi | hdpi |
240dpi~320dpi | xhdpi |
320dpi~480dpi | xxhdpi |
480dpi~640dpi | xxxhdpi |
可以看出403dpi处于320dpi~480dpi之间,因此属于xxhdpi范围。
当我们使用资源id去引用图片资源时,Android会使用一些规则帮我们匹配最适合的图片。如我们的手机屏幕密度为xxhdpi,那么drawable-xxhdpi文件夹下的图片就是最适合的。因此但我们引用资源id去加载图片时,就会优先去drawable-xxhdpi文件夹下去找这张图,如果这个文件夹下没有这张图片,那么会优先去更高密度的文件夹下去找这张图,若发现没有更高密度的文件夹时,就会去drawable-nodpi文件夹下找这张图,如果发现没有,那就去更低密度文件夹下查找,依次是xhdpi->hdpi->mdpi->ldpi。
总体的匹配规则就是这样,如果说这张图最终在mdpi文件夹下找到,此时系统会认为这张图是为低密度屏幕设计的,如果直接将这张图在当前高密度屏幕显示可能出现像素过低的情况,于是系统帮我们做了放大操作。同理,如果系统是在高密度文件夹下找到这张图,系统会帮我们做缩小操作。
另外,刚才在介绍规则时提到一个drawable-nodpi文件夹,这个文件夹是一个与密度无关的文件夹,放在这里的图片系统不会对其进行缩放操作,原图片多大就会实际展示多大。drawable-nodpi文件夹是在匹配密度文件夹和高密度文件夹都找不到的情况下才会去这里查找图片,因此放在drawable-nodpi文件夹里的图片通常情况下不建议再放到别的文件夹里。
图片被缩放的原因找到了,那么缩放比例是怎么确定的呢?规律总结如下:mdpi密度的最大值为160dpi,而xxhdpi密度的最大值为480dpi,当屏幕密度为xxhdpi时,去加载mdpi文件夹下的图片,那么图片将被放大480/160=3倍,同理,若去加载xxxhdpi文件夹下的图片时,图片将缩小480/640=0.75倍。
通常,公司的ui只会给一套图片资源,那么这一套资源应该放在哪个资源密度的文件夹下呢?一张图被缩小没有什么副作用,但是一张图被放大就意味着要占用更多的内存。因此图片资源应放在高密度的文件夹下,而ui设计时也应该尽量面向高密度屏幕的设备来设计。就目前来讲,最佳放置图片的文件夹为drawable-xxhdpi。为什么不放在更高的drawable-xxxhdpi文件夹下呢?那是因为市面上在这个密度区间的设备太少了,如果针对这种级别的密度进行设计,图片在不缩放的情况下本身就已经很大了,基本也起不到节省内存开支的作用了。
Bitmap内存计算
Bitmap单个像素的字节大小由Bitmap的一个可配置参数Config来决定。Config为一个枚举类,详情如下:
Config | 占用字节大小 | 说明 |
---|---|---|
ALPHA_8(1) | 1 | 单透明通道 |
RGB_565(3) | 2 | 简易RGB色调 |
ARGB_4444(4) | 4 | 已废弃 |
ARGB_8888(5) | 4 | 24位真彩色 |
RGBA_F16(6) | 8 | Android 8.0新增(更加丰富的色彩表现HDR) |
HARDWARE(7) | Special | Android 8.0新增(Bitmap直接存储在graphic memory) |
在Android系统中,默认Bitmap加载图片,使用ARGB_8888模式。
Bitmap占用内存大小的公式如下:
Bitmap内存占用≈像素数据总大小=图片宽x图片高x(设备屏幕密度区间最大值/资源文件夹密度区间最大值)^2x每个像素的字节大小。
如一张800x600大小的图片放在mdpi文件夹下,那么在xhdpi设备上加载它的时候,它的内存占用为800x600x(320/160)^2x4=7680000。
Bitmap的高效加载
我们编写的应用程序是有一定内存限制的,程序占用过高的内存就容易出现OOM(out of memory)错误,我们可以通过如下代码得到应用程序的最高可用内存:
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
Log.e("tag", "-------->>" + maxMemory+"kb");
因此,在展示高分辨率图片的时候,最好先将图片进行压缩。压缩后图片的尺寸大小应该和用来展示它的控件大小相近。
BitmapFactory类提供了多个解析方法用于创建