Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / Android

Becoming Resourceful with Android Resources

4.98/5 (26 votes)
25 Jun 2015CPOL27 min read 33.1K   869  
Becoming proficient and competent in managing Android Resources.
Image 1
Click on Me to View a Demo Video

Introduction

Behind every Android app, lies the code that provides the functionalities as well as the resources that support those functionalities. Resources are anything and everything that can be digitized for use in your code, such as text strings, layouts, animation, graphics, colors, and any other static data that your Android app needs. Android's best practices advocate the principle of "separation of concerns" - separating the code and its resources. In this respect, Android framework has provided a systematic way of implementing this principle. You may write excellent code but poorly managed resources will adversely affect the performance of your app. Therefore, it is vital for every Android developer to understand how to manage resources in Android apps effectively and efficiently.

Separation of Concerns

Why do we want to separate the code and its resources? I bet you will ask this question. Well, the reasons are threefold - Reusability, Maintainability, and Alternatives.

  • Reusability: Creating a resource for a particular usage and reuse it as often as the same usage is needed anywhere in your app reduces the overhead. For example, instead of hard coding the captions of all the buttons in your app to take the same value of "Enter", you should create a string resource that takes the value "Enter", and then have every button referencing this string resource.

  • Maintainability: When you only have one resource for each usage, you can change the resource value all at once when the need arises without the having to change the code. For example, you can change the value of the string resource from the previous example from "Enter" to "Submit" and the change will apply to all the buttons in your app instantly, there is no need to bother the code at all. Isn't that wonderful!

  • Alternatives: Given the myriad variety of device configurations, such as screen densities, orientations, and languages, there is no "one-size-fits-all" resource. By separating resources from code, you are able to provide alternative resources for different configurations without the need to modify the code.

So the bottom line is "leave the code alone".

Walking the Talk

What better way to learn how to manage the Android resources than to try it out yourself. We will build a simple app that involves as many resource types as possible so that you can gain a first-hand experience in handling them. In other words, we will walk the talk.

Before attempting the walk, you should have read my previous articles - Creating a Simple Hello World Android Project and Android UI Layouts and Controls as I will not be repeating the nitty-gritty stuff such as how to create an Activity in Android Studio.

Setting the Stage

  • Fire up your Android Studio.

  • Create a new Project called "AndroidResources" (Figure 1).

    Image 2
    Figure 1: Create a New Project
  • Create a new Activity called "MainActivity" (Figure 2).

    Image 3
    Figure 2: Create a New Activity

String Resource

The XML layout file for the "MainActivity" is called the "activity_main.xml". It comes with a default layout of RelativeLayout and a default TextView that says "Hello world!" (Figure 3).

Image 4
Figure 3: MainActivity

You will modify this TextView as follows:

  • Open the "activity_main.xml" in Text view, the <TextView> node should look like this:

    <TextView
       android:text="@string/hello_world"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content" />  

    If you see "Hello World!" instead of "@string/hello_world" for the android:text attribute, just double-click it.

  • The "Hello World!" is not hard coded, it is referenced from this string resource called "hello_world". Where to find it? It is residing in this file called "strings.xml" at res/values/ (Figure 4)

    Image 5
    Figure 4: strings.xml
  • For every string resource that you create in the "strings.xml", the Android builder will create a new static integer in the string class inside "R.java", so that you can refer to it in code by "R.string.hello". If you care to peek into the "R.java", it is located here: (Figure 5)

    Image 6
    Figure 5: strings.xml
  • You can change the value of the "hello_world" element from "Hello World!" to "Hello, Code Project!" in "strings.xml" and see the effect instantly (Figure 6).

    <string name="hello_world"><string name="hello_world">Hello, Code Project!</string></string>
    Image 7
    Figure 6: Changed Value
  • Can I set the value of the TextView on the fly, I mean during runtime via code? Of course, you can. But to do that, you have to first assign a value to the "android:id" attribute of the TextView in the "activity_main.xml" so that it can be referred to in the code. You will also delete the "android:text" attribute as its value will be assigned in the code.

    <TextView
        android:id="@+id/hello"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    The + sign inside this "@+id/hello" is Android's way of telling the builder to create a new static integer in the id class inside "R.java", so that you can refer to it in code by "R.id.hello". If you peek into the "R.java" again, you should find it there (Figure 7)

    Image 8
    Figure 7: R.java

    Open the "MainActivity.java" and add the highlighted code in Figure 8. The first line of code finds the TextView by passing "R.id.hello" to "findViewById()" method. The second line gets the string value from the string resource via "R.string.hello_world". The last line of code sets its text attribute to the string value.

    Image 9
    Figure 8: MainActivity.java

    As the new text value only takes effect at runtime, you will have to test it on an AVD or a physical device in order to see its effect (Figure 9).

    Image 10
    Figure 9: On the fly!
Learning Point 1:

When you need a new string value, always create a string resource to hold that string value inside the "strings.xml" like the following example:

<resources>
    <string name="app_name">AndroidResources</string>
    <string name="hello_world">Hello, Android!</string>
    <string name="action_settings">Settings</string>
</resources>

Whenever you need to use this value, you will refer to the name of the string resource that holds this value. There are two ways to access a string resource:

  • In XML,
    @string/<name of string resource>

    For example,

    @string/hello_world
  • In code,
    R.string.<name of string resource>

    For example,

    R.string.hello_world

Color Resource

Create a new resource file called "colors.xml" located at res/values/ directory (Figure 10). "colors.xml" is the default resource file for storing color resources.

Image 11
Figure 10: Create New Resource file

Open the "colors.xml" in the Text view, and add a new color element called "customColor" that takes a color value of "#421d49".

<resources>
    <color name="customColor">#421d49</color>
</resources>

Dimension Resource

Open the "dimens.xml" located at res/values/ directory in the Text view. "dimens.xml" is the default resource file for storing dimensional values. Add a new dimension resource called "text_size" that takes the value of "30sp" like this:

<dimen name="text_size">30sp</dimen>

Style Resource

Open the "styles.xml" located at res/values/ directory in the Text view. "styles.xml" is the default resource file for storing styles and themes. Add a new style resource called "customStyle" with six items as shown:

<style name="customStyle">
    <item name="android:layout_width">match_parent</item>
    <item name="android:layout_height">wrap_content</item>
    <item name="android:gravity">center_horizontal</item>
    <item name="android:textSize">@dimen/text_size</item>
    <item name="android:textColor">@color/customColor</item>
    <item name="android:typeface">serif</item>
</style>

Take note that:

  • the name of the style item takes after the attribute name, e.g. "android:layout_width" and "android:gravity".

  • Two of these items, i.e. "android:textSize" and "android:textColor" are assigned values from the respective resource files of "dimens.xml" and "colors.xml" that you have created earlier. In general, you refer to resources in XML like this:

    @resourceType/<name of resource>

Applying Custom Style to TextView

Let's apply the custom style you have just created to the TextView on "MainActivity".

Open the "activity_main.xml" in Text view, delete the "android:layout_width" and "android:layout_height" attributes, and add the style attribute as follows:

<TextView
    style="@style/customStyle"
    android:id="@+id/hello" />

Run it on an AVD, and there you are (Figure 11).

Image 12
Figure 11: Create New Resource file
Learning Point 2:

You can reference a resource from another resource file. You have done that in the custom style resource which incorporates the color resource and dimension resource. In general, there are two ways to reference a resource,

  • In XML,
    @<resourceType>/<name of resource>

    For example,

    @dimen/text_size
  • In code,
    R.<resourceType>.<name of resource>

    For example,

    R.dimen.text_size

Property Animation

Android framework provides this property animation system whereby you can animate any object by changing its property over time. You can read the details about how property animation works from Android Developers. Let's make a simple property animation by changing the value of the "alpha" property of the TextView on "MainActivity".

  • Create a new resource directory called "animator" inside the "res/" directory. The "animator" directory is the default directory for storing all the property animation resources.

  • Inside the "animator" directory, create a new resource file called "property_animation.xml", and add the following content:

    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <objectAnimator
            android:propertyName="alpha"
            android:duration="2000"
            android:repeatCount="infinite"
            android:repeatMode="reverse"
            android:valueFrom="0.0"
            android:valueTo="1.0" />
    </set>

    This XML file has declared a property animation schema to animate the "alpha" property of any object from total transparency to total opacity in 2 seconds and vice versa infinitely.

  • Open the "MainActivity.java", and add the highlighted code as shown in Figure 12. The code will first inflate the XML resources to an AnimatorSet object, then set the TextView as the target object for animation via the "setTarget()" method, before calling the "start{}" method to start the animation.

    Image 13
    Figure 12: Code to Activate Property Animation
  • Run it on an AVD, you should see that the "Hello, Code Project!" fading in and out repeatedly.

View Animation

Android framework provides this view animation system whereby you can perform tweened animation on any View. A tweened animation performs a series of simple transformations like moving, re-sizing, and rotation on the content of a View object by calculating the in-between frames based on a set of information like the start point, end point, rotation, etc. You can read the details about how View animation works from Android Developers. Let's make a simple tween animation to rotate an image on "MainActivity".

  • Add an ImageView to the "activity_main.xml" below the TextView and assign the default "ic_launcher" drawable Image 14 as its image source like this:

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/robotImage"
        android:src="@drawable/ic_launcher"
        android:layout_below="@+id/hello"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="107dp" />
  • The image appears too small, let's make it bigger. How should we do it? Use dimension resource. In the "dimens.xml" add two new <dimen> elements called "image_height" and "image_width" and both take the value of 100dp as shown:

    <dimen name="image_height">100dp</dimen>
    <dimen name="image_width">100dp</dimen>

    Move back to the "activity_main.xml" and change the "android:layout_width" and "android:layout:height" of the ImageView to point to the two new dimension resources that you have just created as shown:

    android:layout_width="@dimen/image_width"
    android:layout_height="@dimen/image_height"

    The image should appear bigger now with 100dp for width and height respectively.

  • Create a new resource directory called "anim" inside the "res/" directory. The "anim" directory is the default directory for storing all the View animation resources.

  • Inside the "anim" directory, create a new resource file called "tween_animation.xml", and add the following content:

    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <rotate
            android:fromDegrees="0"
            android:toDegrees="360"
            android:repeatCount="infinite"
            android:repeatMode="restart"
            android:pivotX="50%"
            android:pivotY="50%"
            android:duration="2000" />
    </set>

    This XML file has defined a tween animation schema to rotate a View around its center coordinates in 2 seconds repeatedly.

  • Open the "MainActivity.java", and add the highlighted code as shown in Figure 13. The code will locate the ImageView, load the animation schema, and then apply the animation schema to animate (rotate) the ImageView.

    Image 15
    Figure 13: Code to Activate Tween Animation
  • Run it on an AVD, you should see the Android Robot rotating clockwise while the "Hello, Code Project!" fading in and out repeatedly (Figure 14)

    Image 16
    Figure 14: Animation at Work!

ColorStateList

A ColorStateList is an object that defines a list of colors to appear under different states, such as state_pressed, state_focused, and neither. States provide confirmation of clicks and selections. It can be applied to a View to change its color depending on the state of the View. For example, a Button can be in any one of these three state - pressed, focused, or neither. Using a ColorStateList, you can provide a different color for each state. During each state change, the state list is traversed from top to bottom and the first item that matches the current state will be used. Therefore, you should put the default selection as the last item so that it will be picked up when all the above are not met.

  • Create a new resource directory called "color" inside the "res/" directory. The "color" directory is the default directory for storing all the ColorStateList resources.

  • Inside the "color" directory, create a new resource file called "button_state.xml", and add the following content:

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
    
        <item android:state_pressed="true"
            android:color="#ff0000"/> <!-- pressed red -->
    
        <item android:state_focused="true"
            android:color="#0000ff"/> <!-- focused blue -->
    
        <item android:color="#000000"/> <!-- default black -->
    
    </selector>

    This XML file has defined a different color for each state of a View, "red" when pressed, "blue" when focused, and "black" when neither.

  • Add a string resource to the "strings.xml" as shown:

    <string name="click_me">Click Me!</string>
  • Add a Button to the "activity_main.xml" below the Android Robot as shown:

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/click_me"
        android:textColor="@color/button_state"
        android:id="@+id/button"
        android:layout_alignParentBottom="true"
        android:layout_alignRight="@+id/robotImage"
        android:layout_alignEnd="@+id/robotImage"
        android:layout_marginBottom="109dp" />

    Note that I have used a string resource called "click_me" for the "android:text" attribute. You should be able to create this already. The main focus is the android:textColor attribute which is pointing to the "button_state.xml" that you have just created. In this way, the button will take on different colors at different states as dictated by the ColorStateList in the "button_state.xml".

  • We are done with ColorStateList, test it out on your AVD.

Menu

We will add two menu items in the action bar of the "MainActivity". The default directory for all menu resources is "res/menu".

  • First, add two new string resources in the "strings.xml" for labeling the two menu items later on, do this:
    <string name="action_file">File</string>
    <string name="action_help">Help</string>
  • Inside the "menu" directory, it should have a default "main.xml" file, otherwise just create one. Overwrite its content as follows:

    <menu xmlns:android="http://schemas.android.com/apk/res/android">
    
        <item android:id="@+id/action_file"
        android:title="@string/action_file"
        android:showAsAction="never" />
    
        <item android:id="@+id/action_help"
            android:title="@string/action_help"
            android:showAsAction="never" />
    
    </menu>

    This XML file has defined two menu items called "File" and "Help" respectively.

  • Open the "MainActivity.java", add or modify the following code accordingly as shown in Figure 15. The "onCreateOptionsMenu()" method will inflate the "menu.xml" and add its items to the action bar. The "onOptionsItemSelected()" method will be called whenever an menu item is selected, for this exercise, it will simply echo the name of the selected item in a Toast message.

    Image 17
    Figure 15: Code to Handle Menu

Mission Accomplished!

Well done, you have completed a mission to explore the various Android resources. Watch the fruit of your labor from Figures 16 to 18.

Image 18
Figure 16: App in Action!
Image 19
Figure 17: App in Action!
Image 20
Figure 18: App in Action!

Putting Resources into Perspective

From the hands-on exercise, you have learned that Android organizes resources in the project's "res/" directory, using various sub-directories that group resources by type and configuration (Figure 19). There is no better time to sort them out and put them into perspective.

Image 21
Figure 19: Inside res/

Android has been quietly compiling all the resources into a Java class called "R.java". R stands for "Resources". Whenever your app is compiled, Android generates/regenerates the R class, which contains resource IDs for all the resources in the "res/" directory of your project. For each type of resource, there is an R subclass. For example, "R.string" for all string resources. Each resource is assigned a unique integer as its resource ID so that you can use to retrieve the resource. You can find all the resources that are used in the project being declared as public static final int variables in their respective Java classes which are also public static final. As they are subclasses of R, they can be accessed by calling "R.<class name>", e.g. "R.string".

We will go through the resource directories one by one.

  • anim directory contains XML files that define View Animations. Each anim XML file defines a single View animation resource that can be accessed by its file name:

    • In XML,
      @anim/<XML file name>

      For example,

      @anim/tween_animation
    • In code,
      R.anim.<XML file name>

      For example,

      R.anim.tween_animation
  • animator directory contains XML files that define Property Animations. Each animator XML file defines a single property animation resource that can be accessed by its file name:

    • In XML,
      @animator/<XML file name>

      For example,

      @animator/property_animation
    • In code,
      R.animator.<XML file name>

      For example,

      R.animator.property_animation
  • color directory contains XML files that define Color State List Resources. Each color XML file defines a single color state list resource that can be accessed by its file name:

    • In XML,
      @color/<XML file name>

      For example,

      @color/button_state
    • In code,
      R.color.<XML file name>

      For example,

      R.color.button_state
  • drawable directory contains drawable resources like bitmap files and shapes. Drawable resources are further optimized into different sizes to suit different screen resolutions. They are stored in separate directories, namely drawable-mdpi, drawable-hdpi, drawable-xhdpi, and drawable-xxhdpi. The Android operating system will select one of these images for display based on the screen resolution of the device. To find out more about how Android supports multiple screens, visit Android Developers. Each drawable XML file defines a single drawable resource that can be accessed by its file name:

    • In XML,
      @drawable/<XML file name>

      For example,

      @drawable/ic_launcher
    • In code,
      R.drawable.<XML file name>

      For example,

      R.drawable.ic_launcher
  • layout directory contains XML files that define the visual structure for a user interface in Android. This topic has been dealt with extensively in my article Android UI Layouts and Controls. There is only one layout file "activity_main.xml" in your project.

  • menu directory contains all the menu resources like the option menu, action bar, context menu, and pop up menu that you can use in your Android project. There is only one menu resource file "main.xml" in our project. You have created an action bar with two menu items defined in the "main.xml" file. Each menu XML file defines a single menu resource that can be accessed by its file name:

    • In XML,
      @menu/<XML file name>

      For example,

      @menu/main
    • In code,
      R.menu.<XML file name>

      For example,

      R.menu.main
  • raw directory contains arbitrary files of any type saved in raw forms that are not compiled by the Android platform. To access these resources at runtime is similar to access files using "InputStream" like this:

    InputStream inputStream = getResources().openRawResource(R.raw.filename);
  • values directory contains XML files that in turn contain simple values resources, such as colors, dimensions, strings, and styles. Unlike XML resource files in other sub-directories of "res/" which define a single resource for each XML file, each XML file in the "values/" directory define multiple resources. It takes the format like this:

    <resources>
        <resourceType name="resourceName">value</resourceType>
    </resources>

    For example, in "strings.xml"

    <resources>
        <string name="app_name">AndroidResources</string>
        <string name="hello_world">Hello, Code Project!</string>
        <string name="click_me">Click Me!</string>
        <string name="action_file">File</string>
        <string name="action_help">Help</string>
    </resources>
    • color.xml defines color values

    • dimens.xml defines dimension resources. Android uses dp and sp as the recommended units of measurement.

      dp is short for density-independent pixels. You can use dip too. They are the same. It is density independent in the sense that when you define something of 16dp or 16 dip, it would be rendered the same size on any screen. What a perfect solution for the myriad screen sizes of Android devices. It is the recommended unit of dimensions for Android app. Of course, there is no stopping you from using some other units of measurement.

      Android has another unit created specifically for text. It is called scale-independent pixels or sp in short. It is similar to dp but with one twist - it would allow users to change font size without affecting the size of other elements. You are recommended to use sp for any text in Android.

    • strings.xml defines the string resources.

    • styles.xml defines the styles and themes.

    Each value resource in the XML file can be accessed by a combination of its resource type and resource name:

    • In XML,
      @<resourceType>/<name of resource>

      For example,

      @string/app_name
    • In code,
      R.<resourceType>.<name of resource>

      For example,

      R.string.app_name
  • xml directory contains arbitrary XML files that are accessible at runtime using "XmlResourceParser" like this:

    XmlResourceParser xml = getResources.getXml(R.xml.filename);

Providing Alternatives

The resources that are stored in the various sub-directories of "res/" that we have discussed so far are the so-called "default" resources. But they are not enough to cater to the diverse usages and configurations of Android devices owing to changes occur during runtime or localization issues. For example, the default layout that looks good on portrait orientation may look awful on landscape orientation. For that, you will have to provide alternative layout for the later that takes advantage of the extra width. Or, your default string resources that work fine in the current locale may not be suitable for other locales. For that, you will have to provide alternative string resources The bottom line is "you should provide alternative resources, in addition to the default ones."

The Android framework provides a systematic way of providing alternative resources and is able to loads the appropriate resources for your apps based on the device configuration detected at runtime. Let's see how this works by doing a simple exercise to create alternative string resources for a different locale in Japanese in your app.

  • Create a new values resource directory called "values-ja" ("ja" is the qualifier for "Japanese") inside the "res/" directory.

  • Inside the "values-ja" directory, create a new resource file called "strings.xml", and add the following string resources:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <string name="hello_world">こんにちは, Code Project!</string>
        <string name="click_me">クリック!</string>
        <string name="action_file">ファイル</string>
        <string name="action_help">助け</string>
    </resources>  
  • That's it! You have just created alternative string resources for "Japanese" language setting. Try it out on an AVD, set its language setting to Japanese and you should see your app appearing in Japanese (Figure 20) or watch this video. Note that the app name "AndroidResources" remains intact as it is not defined in the alternative resource, so the default resource prevails. Have you touched any code? No! What a wonderful Android.

    Image 22
    Figure 20: String Resources in Japanese

So what have you done to create alternative resources? Let's recall:

  • Inside the "res/" directory, create a new sub-directory named in this format:
    <resourceType>-<qualifier>

    For example,

    values-ja
    • <resourceType> is the directory name of the corresponding default resource types such as anim, layout, menu, values, and so on.

    • <qualifier> is a name that indicates the specific device configuration under which the alternative resources should be used. (Details in Table 1)

  • Inside this "<name of resource>-<qualifier>" directory, create your alternative resource files using the exact same names as their counterparts in the default resource directories. For example, "tween_animation.xml", "main.xml", "strings.xml", "dimens.xml", and so on. In the case of values resource files such as "colors.xml", "strings.xml", you should use the exact same resource name for each element contained in the alternative value resource files. For example, compare the default "strings.xml" in the default "values" directory to the alternative "strings.xml" in the "values-ja" directory shown here:

    • "values/strings.xml"

      <?xml version="1.0" encoding="utf-8"?>
      <resources>
          <string name="app_name">AndroidResources</string>
          <string name="hello_world">Hello, Code Project!</string>
          <string name="click_me">Click Me!</string>
          <string name="action_file">File</string>
          <string name="action_help">Help</string>
      </resources>
    • "values-ja/strings.xml"

      <?xml version="1.0" encoding="utf-8"?>
      <resources>
          <string name="hello_world">こんにちは, Code Project!</string>
          <string name="click_me">クリック!</string>
          <string name="action_file">ファイル</string>
          <string name="action_help">助け</string>
      </resources>  

In a nutshell, the qualifier names serve as important cues to the Android system as to which alternative resources to adopt under a specific configuration. Android supports many qualifiers for denoting alternative resources, see Table 1 for details.

Table 1: Alternative Resource Qualifiers
Type Qualifier Elaboration

Mobile Country Codes (MCC)

Mobile Network Codes (MNC)

Examples:
mcc310-mnc070 belongs to
AT&T Wireless Inc

mcc525-mnc07 belongs to Singapore Singtel

MCC is used in mobile networks (GSM, CDMA, UMTS, etc.) to  uniquely identify the country which a mobile subscriber belongs to. It is often used together with MNC to uniquely identify a mobile subscriber's network.

Read more from mcc-mnc.com.

Language and region Examples:
en
en-rGB
en-rSG
en-rUS
fr
fr-rCA
fr-rFR

The language is defined by a two-letter ISO 639-1 language code, e.g. en for English.

Optionally, it may be appended with a dash "-" and a lowercase "r" followed by two letter ISO 3166-1-alpha-2 region code. e.g. en-rSG stands for English in Singapore.

Layout Direction ldltr

ldrtl

ldltr stands for "layout-direction-left-to-right" and is the default layout direction for any Android apps.

ldrtl stands for "layout-direction-right-to-left".

This can be applied to any resource such as layouts, drawables, or values.

However, the ldrtl only works for devices that are of API level 17 or above. To enable ldrtl for your app, you have to set the android:supportsRtl attribute to "true" and the targetSdkVersion to 17 or higher in the AndroidManifest.xml.

Smallest Width sw<N>dp

Examples:
sw600dp
sw720dp

This specifies the smallest width in <N>dp to be used by a resource,  regardless of the screen orientation.

Available Width w<N>dp

Examples:
w820dp
w1024dp

This specifies a minimum available screen width, in <N>dp to be used by a resource the value of which will change when the orientation changes between landscape and portrait to match the current width.

Available Height h<N>dp

Examples:
h720dp
h1024dp

This specifies a minimum available screen height, in <N>dp to be used by a resource the value of which will change when the orientation changes between landscape and portrait to match the current height.

Screen Size small

normal

large

xlarge

small: Screens that are approximately 320x426 dp. Examples are QVGA low density and VGA high density.

normal: Screens that are approximately 320x470 dp. Examples are WQVGA low density, HVGA medium density, WVGA high density.

large: Screens that are approximately 480x640 dp. Examples are VGA and WVGA medium density screens.

xlarge: Screens that are approximately 720x960 dp. In most cases, they belong to tablet-style devices.

Screen Aspect long

notlong

long screen includes WQVGA, WVGA, FWVGA.

notlong screen includes QVGA, HVGA, and VGA.

Screen Orientation port

land

port for portrait whereby the height is more than the width.

land for landscape whereby the height is less than the width.

This change will occur during runtime whenever the users rotate their devices.

UI Mode

car

desk

television

watch

appliance

car mode is set for devices that are displaying in a car dock.

desk mode is set for devices that are displaying in a desk dock.

television mode is set for devices that are displaying on a television.

watch mode is set for devices that have a display and are worn on the wrist.

appliance mode is set for devices that are serving as an appliance, with no display unit.

Night Mode night

notnight

night for night time.

notnight for day time.

Screen Density

ldpi

mdpi

hdpi

xhdpi

xxhdpi

nodpi

tvdpi

ldpi for low density screens of approximately 120dpi.

mdpi for medium density screens of approximately 160dpi.

hdpi for high density screens of approximately 240dpi.

xhdpi for extra high density screens of approximately 320dpi.

xxhdpi for even higher density screens of approximately 480dpi.

nodpi for density-independent resources that you do not want to be scaled regardless of the current screen density.

tvdpi for screen density of approximately 213dpi. It is mostly intended for televisions.

Touchscreen Availability finger

notouch

finger denotes that the device has a touchscreen.

notouch denotes that the devices does not have a touchscreen.

Keyboard Availability

keysexposed

keyshidden

keyssoft

keysexposed denotes that the device has a hardware keyboard.

keyshidden denotes that the device has a hardware keyboard but it is hidden and it does not have a software keyboard enabled.

keyssoft denotes that the device has a software keyboard enabled.

Primary text input method

nokeys

qwerty

12key

nokeys denotes that the device has no hardware keys for text input.

qwerty denotes that the device has a hardware qwerty keyboard.

12key denotes that the device has a hardware 12-key keyboard,.

Navigation Keys Availability

navexposed

navhidden

navexposed denotes that navigation keys are available to the user.

navhidden denotes that navigation keys are not available.

Primary Non-touch Navigation Method

nonav

dpad

trackball

wheel

nonav denotes that the device has no other navigation facility other than the touchscreen.

dpad denotes that the device has a directional-pad (d-pad) for navigation.

trackball denotes that the device has a trackball for navigation.

wheel denotes that the device has a directional wheel for navigation.

API level

Examples:
v1
v4
v19

This denotes the API level supported by the device. For example, v1 for API level 1 and v4 for API level 4. Refer to the Android API levels document for more information about these values.

Observing the Rules

There are a number of rules to observe when it comes to providing alternative resources:

  • You cannot nest a resource directory in another resource directory. For example, "res/values/values-ja/" is illegal.

  • You can add multiple qualifiers of different types to a single resource directory name, by separating each qualifier with a dash "-". For example, "values-en-rSG-port" applies to Singapore-English devices in portrait orientation.

  • However, you must add them to the directory name in the order that they are listed in Table 1. Take the previous example, "values-port-en-rSG" is not acceptable.

  • You cannot add multiple qualifiers of the same types to a single resource directory name. For example, "layout-land-port" makes no sense.

Best Practices

As we are approaching the rest stop, I have rounded up some best practices that you should follow in order to manage the resources in your Android app correctly and efficiently.

Separation of Concerns

I have to stress this point again for the reasons that I have mentioned at the beginning of this article. Separate resources from code. Never hard code even a string value or number, assign it to an appropriate resource type, then you can refer to it as and when you need it.

Providing Default Resources

You do not have to provide alternative resources for each type of resource that your app uses, but you definitely must provide a complete set of default resources. Why? Imagine you store all the resources in directories that have a qualifier. When your app tries to run on a device that does not have any of those configurations specified by the qualifiers, it will crash! If you have provided the resources in the default resource directories, i.e. directories without any qualifier, you app will switch to use these default resources and continue to run properly.

In the exercise on localization that you have done earlier, you have provided an alternative string resources for Japanese alongside the default one in English. The Japanese version one did not have all the string resources that the default one has. (I have purposely left out the "app_name".) But that is fine, as the absent alternative resource will be covered up by the corresponding default one as long as it is there. That is why the default resources must be provided for all type of resource that you app uses.

Another reason to provide default resources is that your app may run on older versions of Android devices that do not recognize some of the newer qualifiers introduced in the latest versions. Again, that will cause the app to crash if there is no default resources to fall back to.

So, the right way to providing resources is to always provide default resources for all type of resource that your app needs to perform properly. Then create alternative resources for specific device configurations using the appropriate qualifiers.

You may notice one contradiction in our project. There is no default "drawable" directory! Well, this is an exception as explained by Android Developers:

Quote:
There is one exception to this rule: If your application's minSdkVersion is 4 or greater, you do not need default drawable resources when you provide alternative drawable resources with the screen density qualifier. Even without default drawable resources, Android can find the best match among the alternative screen densities and scale the bitmaps as necessary. However, for the best experience on all types of devices, you should provide alternative drawables for all three types of density.

Avoid Over-Providing Alternatives

Although you have to provide a full set of resources that your app needs, your alternative resources do not have to have everything the default has. For example, there is hardly any need for an alternative layout when you plan for a locale-specific alternative. However, you may need alternative layout to cater to screen orientation change during runtime. Study the requirements carefully will help you to establish what alternative resources your app really needs. That will help to reduce development time and cost and ease maintenance subsequently.

Testing for Default Resources

You should test your app for all default resource types, be it language, orientation, screen size, and so on. For example, testing you app by setting the test device to a language that is not supported in your app. If the app crashes, that suggests missing strings in the default string resource directory. Do the same testing for other resource types.

Tips

I have placed some resource-related tips here to help you in developing your Android app.

Providing Different Bitmap Drawables to Match Different Screen Densities

By default, Android scales your bitmap drawables so that they can be rendered appropriately on different screen sizes. However, the result of such auto scaling is not optimal. Instead, you are advised to provide different resolutions of the drawable targeting at different screen densities.

Providing Different Layouts for Different Screen Sizes

By default, Android resizes your app layout to fit into different device screen. However, forcing a small size shirt onto a large torso and vice versa is anything but good. Instead, you should provide different layouts targeting at different screen sizes.

Declaring Screen Sizes Explicitly

You should declare screen sizes explicitly that your app supports by including <supports-screens> element in the manifest file of your app. In this way, you can ensure that only devices with the matching screen size can download your app.

At the Rest Stop

We have arrived at the rest stop. It has been a resourceful journey. This journey started off with you doing a hands-on exercise to explore, create, and provide different resource types to an Android app. Among other things, you have learned how Android organizes resources, the best practices in providing default as well as alternative resources, and the different ways of accessing resources. I hope you have become more resourceful in managing Android resources from now on.

Reference

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)