androidpixeldpidensity-independent-pixelpixel-density

Why displayMetrics.density is wrong?


On my Pixel 7 device, I want to know how many density-independent pixels (dp) I have. So, I use this formula:

displayMetrics.widthPixels / displayMetrics.density

However, I have an issue because displayMetrics.widthPixels = 1080 (which is okay) and displayMetrics.density = 2.625. When I calculate 1080 / 2.625, it equals 411.428571 density-independent pixels, which is not an integer. It seems that displayMetrics.density = 2.625 may be incorrect because it's unusual to have a fraction of a density-independent pixel.

How can I obtain the correct value for displayMetrics.density? I suppose it's 2.62135922, which would result in 412 density-independent pixels, making it seem more visually appealing.


Solution

  • Looking at the Android's official dp-px conversion formula, one can say your calculation as such is correct. And displayMetrics.density is not wrong. The thing is, that

    One dp is a virtual pixel unit that's roughly equal to one pixel on a medium-density screen (160 dpi, or the "baseline" density). Android translates this value to the appropriate number of real pixels for each other density.

    This definiton of one dp is platform-dependent, e.g. Windows has another one. So your formula is indeed

        px = dp * (dpi / 160)
    <=> px = dp * displayMetrics.density
    <=> dp = px / displayMetrics.density
    <=> dp = displayMetrics.widthPixels / displayMetrics.density
    

    as density is defined as dpi/160.

    However, as the holy docs say

    Never hardcode this equation

    and one should use applyDimension() for the conversion from dp to px. Analogously, deriveDimension() converts px to dp.

    Now you say: "Wait a moment, deriveDimension() only comes with Android 14. What shall I do in the meantime?"

    Note, that applyDimension() and deriveDimension() both return float values. The docs' example for applyDimension() applies a type conversion to Integer on the result.

    So -- keep using your formula for now and simply add a type conversion of the result to Integer.