Resource Set Rules

Where things start to get complicated is when you need to use multiple disparate criteria for your resources.

For example, suppose that you have drawable resources that are locale-dependent, because they tie into local iconography (e.g., roadside traffic signs). You might want to have resource sets of drawables tied to language, so you can substitute in different images for different locales. However, you might also want to have those images vary by density, using higher-resolution images on higher-density devices, so the images all come out around the same physical size.

To do that, you would wind up with directories with multiple resource set qualifiers, such as:

(with the default language being, say, US English, using an American set of icons)

Once you get into these sorts of situations, though, a few rules come into play, such as:

Given that you can have N different definitions of a resource, how does Android choose the one to use?

First, Android tosses out ones that are specifically invalid. So, for example, if the language of the device is -ru, Android will ignore resource sets that specify other languages (e.g., -zh). The exceptions to this are density qualifiers and screen size qualifiers — we will get to those exceptions later.

Then, Android chooses the resource set that has the desired resource and has the most important distinct qualifier. Here, by “most important”, we mean the one that appears left-most in the directory name, based upon the directory naming rules discussed above. And, by “distinct”, we mean where no other resource set has that qualifier.

If there is no specific resource set that matches, Android chooses the default set — the one with no suffixes on the directory name (e.g., res/layout/).

With those rules in mind, let’s look at some scenarios, to cover the base case plus the aforementioned exceptions.

Scenario #1: Something Simple

Let’s suppose that we have a main.xml layout resource in:

When we call setContentView(R.layout.main), Android will choose the main.xml in res/layout-w640dp/ if the device’s current width is 640dp or larger. That particular resource set is valid in that case, and it has the most important distinct qualifier (-w640dp). If the device has a smaller current width, though, the res/layout-w640dp/ resource set does not qualify, and so it is ignored. That leaves us with res/layout/, so Android uses that main.xml version.

Scenario #2: Disparate Resource Set Categories

It is possible, though bizarre, for you to have a project with main.xml in:

In this case, if the device’s locale is set to be English, Android will choose res/layout-en/, regardless of the orientation of the device. That is because -en is a more important resource set qualifier — “Language and region” appears higher in the “Table 2. Configuration qualifier names” from the Android documentation than does “Available width” (for -w640dp). If the device is not set for English, though, Android will toss out that resource set, at which point the decision-making process is the same as in Scenario #1 above.

Scenario #3: Multiple Qualifiers

Now let’s envision a project with main.xml in:

You might think that res/layout-w640dp-v21/ would be a higher-priority choice than res/layout-en/, as it is more specific, matching on two resource set qualifiers versus the one or none from the other resource sets.

(in fact, the author of this book thought this was the choice for many years)

In this case, though, language is more important than either screen orientation or Android API level, so the decision-making process is similar to Scenario #2 above: Android chooses res/layout-en/ for English-language devices, res/layout-w640dp-v21/ for 4"-wide API Level 21+ devices, or res/layout/ for everything else.

Scenario #4: Multiple Qualifiers, Revisited

Let’s change the resource mix, so now we have a project with main.xml in:

Here, while -w640dp is the most important resource set qualifier, it is not distinct — we have more than one resource set with -w640dp. Hence, we need to check which is the next-most-important resource set qualifier. In this case, that is -night, as night mode is a more important category than is Android API level, and so Android will choose res/layout-land-night/ if the device is in night mode. Otherwise, it will choose res/layout-w640dp-v21/ if the device is running API Level 21 or higher. If the device is not in night mode and is not running API Level 21 or higher — or if the device is less than 4" wide at present — Android will go with res/layout/.

Scenario #5: Screen Density

Now, let’s look at the main exception to the rules: screen density.

Android will always accept a resource set that contains a screen density, even if it does not match the density of the device. If there is an exact density match, of course, Android uses it. Otherwise, it will use what it feels is the next-best match, based upon how far off it is from the device’s actual density and whether the other density is higher or lower than the device’s actual density.

The reason for this is that for drawable and mipmap resources, Android will downsample or upsample the image automatically, so the drawable will appear to be the right size, even though you did not provide an image in that specific density.

The catch is two-fold:

  1. Android applies this logic to all resources, not just drawables and mipmaps, so even if there is no exact density match on, say, a layout, Android will still choose a resource from another density bucket for the layout
  2. As a side-effect of the previous bullet, if you include a density resource set qualifier, Android will ignore any lower-priority resource set qualifiers (unless there are multiple directories with the same density resource set qualifier, in which case the lower-priority qualifiers serve as the “tiebreaker”)

So, now let’s pretend that our project has main.xml in:

Android will choose res/layout-mdpi/, even for -hdpi devices that do not have a “non-touch navigation method”. While -mdpi does not match -hdpi, Android will still choose -mdpi. If we were dealing with drawable or mipmap resources, Android would upsample the -mdpi image.


Prev Table of Contents Next

This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.