Documentation clearly says that mm
and in
are screen size dependent.
mm
Millimeters - Based on the physical size of the screen.in
Inches - Based on the physical size of the screen.
But when I use them, Lint says:
Avoid using "mm" as units (it does not work accurately on all devices); use "dp" instead
Is documentation wrong? And why Lint doesn't warn when using pt
?
pt
Points - 1/72 of an inch based on the physical size of the screen.
To be able to give a good answer to your question I first have to give an explanation on how DPI works in Android, so this answer is a bit long.
TL;DR: The documentation is correct, however the warning from Lint is also correct. That is there are some (buggy?) devices where mm
, in
and pt
doesn't work correctly.
In Android there are two different kinds of density measures that can be accessed from the DisplayMetrics class:
The dp
unit is calculated based on the densityDpi metric while the mm
, in
and pt
units are all calculated based on xdpi/ydpi instead.
It is possible to divide devices into four different categories depending on what values they report for densityDpi and xdpi / ydpi:
Example devices: Samsung Galaxy Trend, Nexus 4, Nexus 7.
For these devices there it doesn't really matter if you use in
, mm
, or dp
. If you draw a square with sides 1 in
and one with 160 dp
they will be the same and both will be about 1 inch on the actual screen.
Category 2 example devices: HTC One S, Sony Xperia V, Sony Xperia Z Ultra.
Category 3 example devices: Samsung Galaxy S4, Sony Xperia Z1, Nexus 5.
For these devices the densityDpi and xdpi / ydpi differs because the densityDpi must be set to one of the available density buckets. So the true physical dpi is rounded to match the nearest bucket and this is what is reported as densityDPI value. This is illustrated by Figure 1 in the Supporting Multiple Screens document.
This means that if you draw a square with side 1 in
and one with 160 dp
they will have slightly different size. For category 2 devices the 160 dp
square will be slightly smaller and for category 3 devices it will instead by slightly larger. If you take out a ruler and physically measure the squares on the screen of the phone you will see that the 1 in
square is 1 inch while the 160 dp
square is a bit smaller or bigger depending on category.
This is a natural consequence of the density buckets system in Android, but unless you have a deeper understanding of how this works it may be a bit surprising that things drawn with a fixed dp measure may look different on different phones.
Example devices: Samsung Galaxy Mini, Samsung Galaxy S3 Mini.
These devices are more problematic, they have a good value for densityDpi (their true dpi rounded to the nearest bucket), but they report bogus values for xdpi / ydpi.
For example Samsung Galaxy S3 Mini reports an xdpi of 160 and densityDpi of 240. The screen 480 px wide so if 160 dpi was correct this would mean a screen width of 3 inch, but in reality the screen with is 2.05 inch. Based on these numbers the actual xdpi value that the phone should be reporting is 234.
Another example is the Samsung Galaxy Mini which also reports an xdpi of 160, but has densityDpi set to 120. That screen is 240 px wide so that would give a physical width of 1.5 inch, but in reality the screen is 1.9 inch (actual xdpi of 126).
So on these types of devices it is not possible to trust the in, mm, pt units since they will result in things being way too small or way too big.
This is three screenshots of a test app I've made taken on devices from category 1, 2 and 3. The green square is drawn to be 1 inch big based on using the xdpi and ydpi values while the red square is drawn to be 1 inch big using dp (160 dp).
When physically measuring the result with a ruler the green square was inch big in all these examples while the red square size differed somewhat as it's visible on the screenshots.
This is a screenshot from a category 4 device. The green and red squares are the same as in the previous example, but here I have also added two more squares, a yellow square that is 1 in
and a blue square that is 72 pt
. As visible on the screenshot all squares except the red square are of equal size.
When physically measuring the result with a ruler the red square is about one inch big while the rest of the squares are only about 0.67 inch big.
The warning from Lint refers to category 4 type devices that return incorrect values for xdpi and ydpi. Since xdpi / ydpi can not be trusted on these devices the units (mm
, in
, pt
) that depend on them can not be trusted either.
Is documentation wrong?
No the documentation is correct, these units are based on the physical size of the screen. However some problematic devices report wrong values for the physical size of the screen (xdpi / ydpi) to Android and then these units will be wrong as well.
And why Lint doesn't warn when using pt?
The Lint developers probably just forgot about pt
, it is just as problematic as in
and mm
.
The reason Lint recommends using dp
instead is because this is a unit that is used extremely frequently in Android so if any device had broken dp
units pretty much all applications would look horrible and it would be fixed before the device was ever released to market.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With