鹰击长空,鱼翔浅底,万类霜天竞自由

Android学习:浅谈各种DPI以及遇到的坑


和 IOS 开发不同,Android 开发需要面临各种屏幕分辨率适配的文问题。Android 中提供了多个存放图片的文件夹,分别为 mdpi、hdpi、xhdpi、xxhdpi、xxxhdpi。Google 文档上说,Andriod 系统会根据手机屏幕的大小及屏幕密度去选择不同文件夹下的图片资源,以此来实现在不同大小不同屏幕分辨率下适配的问题。


要想了解 DPI 就要了解以下几个概念:

1. 分辨率:分辨率就是手机屏幕的像素点数,一般描述成屏幕的“宽×高”,安卓手机屏幕常见的分辨率有480×800、720×1280、1080×1920等。720×1280表示此屏幕在宽度方向有720个像素,在高度方向有1280个像素。

2. 屏幕大小:屏幕大小是手机对角线的物理尺寸,以英寸(inch)为单位。比如某某手机为“5寸大屏手机”,就是指对角线的尺寸,5寸×2.54厘米/寸=12.7厘米。

3. 密度(dpi,dots per inch;或PPI,pixels per inch):从英文顾名思义,就是每英寸的像素点数,数值越高当然显示越细腻。假如我们知道一部手机的分辨率是1080×1920,屏幕大小是5英寸,你能否算出此屏幕的密度呢?通过宽1080和高1920,根据勾股定理,我们得出对角线的像素数大约是2203,那么用 2203除以5就是此屏幕的密度了,计算结果是440。


下面给出一张图来描述下不同 DPI 之间的关系。

26C9362B4F20450E9725383F653452F6T1540795229215W675H358.png

例如: 在一个 1080×1920 分辨率的手机上,Android 就会选择 xxhdpi 文件夹下的图片,但是如果没有在xxhdpi 的文件夹下找见相关的资源文件,Android 系统会首先从 xxxhdpi 文件夹中选择文件,然后对图片资源进行缩放处理,显示在屏幕上;如果 xxxhdpi 文件夹下也没有的话,一次类推,若都没找到话,会在默认的 drawable 文件夹中寻找。说白了的话:在对应的文件夹没找到,就从高分辨率的文件夹依次向低分辨率的文件夹寻找。

在使用时遇到的坑

但是如果不是在对应目录中找到的,而是在其他目录中找到就可能会引发一定的问题。我刚开始写 Android 代码的时候,使用的是 Android Studio,因为 Android Studio 在新建工程的时候,对于 drawable 资源并没有像 mipmap 资源一样,对不同 DPI 创建不同的目录。我把某一个 ImageView 的原图片(1920x1080)直接放在了 drawable 目录下,然后在 ImageView 的 android:src 属性直接引入。

按照当时的了解,这样做完全没问题。我的调试机器屏幕正好是 1920x1080 的屏幕,图片可以正好显示。但是在实际运行的时候就会抛出下面的异常:

W/OpenGLRenderer: Bitmap too large to be uploaded into a texture (3240x5760, max=4096x4096)
Bitmap too large to be uploaded into a texture (3240x5760, max=4096x4096)

很明显提示图片尺寸为 3240x5760,超过了显示的最大尺寸 4096x4096,但是实际的图片尺寸只有 1920x1080。这究竟是为什么?查看一下这几个尺寸的关系,不难得出下面的规律,图片分辨率被放大了3倍。为什么会是3倍呢,然后看上面给出的图,xxhdpi 和 mdpi 比例的倍数正好是 3!

由此得知,放在 drawable 中的图片和放在 drawable-mdpi 中效果一样,当 xxhdpi 的设备在扫描照片时,最终在 drawable 目录中找到,如果按照原比例显示,很明显会导致在 xxhdpi 屏幕上小很多,所以 Android 就将其按照比例进行放大,然后显示。同理,如果拥有 mdpi 的屏幕的设备,在 drawable-xxhdpi 中找到图片资源,就会将其缩小三倍,然后显示。

因为谷歌之所以提出 DPI 的概念,就是要让同样的图片或文字在不同 DPI 设备上显示同样的大小,所以才会导致上面的放大或缩小处理。

写在后面

上面所说到的错误,有可能不会出现。我个人的实验图片是 PNG 格式的,如果采用 JPEG 格式的图片,可能不会出现上面的错误,而是直接抛出 OOM 异常。具体的原因,在此先不进行说明。


版权声明

本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可。 本站博文除注明转载/出处外,均为本站原创或翻译,转载前请务必署名。