Platform Resource Aliases

One of the reasons why I keep close tabs on Stack Overflow is that, every now and then, I’m reminded of a technique that I should be promoting more.

Today’s example of this comes from this question, where a developer inheriting an existing Android Studio project questioned why the project had a res/values/drawables.xml file that contains a bunch of <item> elements:

<resources xmlns:android="http://schemas.android.com/apk/res/android">
    <item name="ic_menu_camera" type="drawable">@android:drawable/ic_menu_camera</item>
    <item name="ic_menu_gallery" type="drawable">@android:drawable/ic_menu_gallery</item>
    <item name="ic_menu_slideshow" type="drawable">@android:drawable/ic_menu_slideshow</item>
    <item name="ic_menu_manage" type="drawable">@android:drawable/ic_menu_manage</item>
    <item name="ic_menu_share" type="drawable">@android:drawable/ic_menu_share</item>
    <item name="ic_menu_send" type="drawable">@android:drawable/ic_menu_send</item>
</resources>

What the original developer did was set up project aliases for platform resources.

There are lots of resources available in the Android SDK. You are welcome to refer to them directly if you want, such as @android:string/ok or android.R.color.black.

However, platform resources have two key problems:

  1. They tend to be very specific. android.R.color.black is a color resource that resolves to black. It should always be black.

  2. They might vary by Android version or even device manufacturer build. Some manufacturer, or even Google itself, might decide that orange is the new black and have android.R.color.black resolve to some shade of orange.

Ideally, you add a bit of indirection here, so that all of your Java code and other resources that today might use platform resources could switch tomorrow to some other implementation of those resources, without having to change all of the references to the resources.

Sometimes, we do this via styles and themes. However, that gets confusing, can be overkill, and does not necessarily cover all scenarios.

Resource aliases are another approach, the one taken by the original developer of the code from the Stack Overflow question. <item> elements, with type pointing to the type of resource, gives us indirection. With the above XML in a project, the project code and other resources can refer to R.drawable.ic_menu_share and such. Right now, the implementations of those drawables happen to be platform resources, by means of the <item> elements. However, later on, you could get rid of the <item> elements and add custom drawables as replacements. Nothing that refers to the resource needs to change, courtesy of the indirection.

Even in cases where you do not think that you will need to switch to a custom resource, using this sort of indirection technique lets you use logical resource names (e.g., R.color.divider instead of android.R.color.black, to make it easier for you to switch to android.R.color.holo_orange_dark later on without other code changes). Again, styles and themes may supplant the need for a lot of these aliases, but not everything belongs in a style resource.