Byte sized bits to cleaner Android code: drawable-dpi

Marko Petrovski
Web Factory LLC
Published in
4 min readOct 22, 2019

With all the options for using different kinds of drawable folders it is easy to get mixed up about which one will be used in what scenario. For now we are just going to focus on the order of precedence with the drawable-dpi folders.

In a nutshell, the reason for all these drawable-x-y combinations is so that we can support different kinds of screen sizes and configurations.

For the rest of the affixes, take a look at the following link: https://developer.android.com/guide/topics/resources/providing-resources.html

Takeaway

The goal of this post is: do NOT put high resolution images in the drawable folder, they will be scaled up and cause an OutOfMemory Exception. The exception is caused by the resolution of the image being up-scaled, not the file size.

Dpi order of precedence

Source: https://developer.android.com/images/screens_support/devices-density_2x.png

What the above image tells us is that Android scales our images based on which dpi density that phone has. If there isn’t an image that is placed in the matching drawable-dpi folder to the device dpi, Android will either scale the image up, or down from its neighbouring drawable-dpi folders. This can get out of hand if not managed properly (Thanks to Dimitar Zabaznoski for the heads up on this one).

We are going to look at in what order android uses these folders for each specific dpi (ldpi, mdpi, hdpi, xhdpi, xxhdpi, xxxhdpi, nodpi).

Keep in mind that resources in drawable-nodpi are density-independent resources. The system does not scale resources tagged with this qualifier, regardless of the current screen’s density.

The images we are going to use contain text in them identifying which folder they come from. They look something like this:

Their specifications are:

  • drawable: 400x400, 5KB
  • drawable-ldpi: 300x300, 5KB
  • drawable-mdpi: 400x400, 6KB
  • drawable-hdpi: 600x600, 9KB
  • drawable-xhdpi: 800x800, 12KB
  • drawable-xxhdpi: 1200x1200, 26KB
  • drawable-xxxhdpi: 1600x1600, 36KB
  • drawable-nodpi : 300x300, 5KB

Each image is scaled according to the above graphic, and in the non-dpi drawable folder we place an image that is the same resolution as our mdpi one. As we will see in the table below, Android has an order of precedence on which drawable-dpi folder to use and does up-scaling / down-scaling accordingly.

If our image is placed in a higher dpi folder than our device is (ex: image placed in xhdpi and our device is mdpi), than the image will be down-scaled, now here comes the tricky part, if our image is placed in a lower drawable-dpi folder than our device is, than up-scaling happens. So imagine if we place our high-resolution image in our drawable / drawable-ldpi / drawable-mdpi folder and we have an xxxhdpi device, it will take our image and scale it x4, and that’s where all the ram usage comes from in the last column of our table below.

So to counter this huge up-scaling, you should place your high resolution images in drawable-xxxhdpi or drawable-xxhdpi, in this way we avoid the massive up-scaling for high pixel density devices and the down-scaling just continues normally.

Findings

Some explanation for the below columns:

  • Emulator / dpi — which emulator was used and what pixel density it had.
  • 1st — if an image is present in all drawable folders, from which folder will the image be taken.
  • 2nd — if we don’t have the image mentioned in the 1st folder i.e the best choice for the device used, what will be the 2nd choice.
  • 3rd — 7th — the same as the 2nd column, remove the 2nd / 3rd / etc. choice and see which one will be chosen next.
  • Ram usage — the average ram used by our application, which was just an ImageView with the above image.
  • Incorrect usage — how much ram is used if we put a high resolution image in our drawable folder.
  • Scaled resolution (1600x1600) — how much our image from the drawable folder will be scaled up. The images initial resolution is 1600x1600.

Example of what this data means, let’s look at Pixel XL, if we have an image in all drawable folders it will first use the drawable-xxxhdpi, if the drawable-xxxhdpi one is missing it will use the image from drawable-xxhdpi, then xhdpi > nodpi > hdpi > mdpi > drawable > ldpi. If we use our drawable folders correctly we will have an average ram usage of ~18.2MB, if we have a high resolution image in our drawable folder and use it, our ram usage will spike to 130.5MB and our image will be scaled to 5600x5600 from 1600x1600.

Conclusion

Avoid placing high resolution images in the drawable folder or other low dpi drawable folders, instead place them in the drawable-xxxhdpi or drawable-xxhdpi folder and eliminate the unnecessary memory hog that up-scaling can become.

Check out part one of this series: Byte sized bits to cleaner Android code: Functions

--

--