Android Fundamentals with Java

Resources: Strings, Colors & Dimensions

18 min Lesson 8 of 12

Resources: Strings, Colors & Dimensions

One of Android's most powerful architectural decisions is the complete separation of values from code. Colors, text, sizes, images — none of these belong hardcoded inside a Java class. They live in XML resource files under res/, and the build system generates a class called R that gives your code type-safe integer handles to each one. This lesson covers the three most important value resource types — strings, colors, and dimensions — and explains how to use them correctly at every level of the stack.

Why Externalize Values?

Consider what happens when you hardcode a color directly in Java:

textView.setTextColor(0xFF1A73E8); // hardcoded hex — avoid this

Now imagine the designer changes the brand color. You must grep through every Java file, find every hex literal, and hope you caught them all. If you later add Arabic support, every hardcoded string becomes a maintenance burden.

With resource files you change one line in colors.xml and every widget that references @color/brand_primary updates automatically — in all layouts, all themes, all screen densities and all languages.

The res/ Directory Structure

Android organizes resources into typed subdirectories under app/src/main/res/:

  • res/values/strings.xml — string constants and plurals
  • res/values/colors.xml — color constants
  • res/values/dimens.xml — dimension constants (dp, sp)
  • res/values/styles.xml — styles and themes
  • res/drawable/ — vector and raster graphics
  • res/layout/ — XML layout files
  • res/values-ar/strings.xml — Arabic string overrides (localization)
  • res/values-night/colors.xml — dark-mode color overrides
Configuration qualifiers are the folder suffixes like -ar, -night, -sw600dp. Android's resource resolver picks the best-matching folder at runtime. Your default values/ folder is the fallback when no qualifier matches. This single mechanism handles localization, dark mode, screen size, density, and orientation — all without a single if statement in Java.

Strings

Every user-visible string should live in res/values/strings.xml:

<!-- res/values/strings.xml --> <resources> <string name="app_name">My App</string> <string name="welcome_message">Welcome, %1$s!</string> <string name="login_button">Log In</string> <string name="items_count">You have %1$d items in your cart.</string> </resources>

Reference a string inside a layout XML with the @string/ prefix:

<Button android:id="@+id/btnLogin" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/login_button" />

Load a string in Java code with getString() — available on any Context (Activity, Fragment, Service):

// Simple string String appName = getString(R.string.app_name); // String with format arguments (%1$s placeholder) String greeting = getString(R.string.welcome_message, "Edrees"); // Result: "Welcome, Edrees!" textView.setText(greeting);
Use format arguments instead of string concatenation. getString(R.string.items_count, cart.size()) lets translators reorder the sentence naturally in their language. With concatenation you force every language into the English word order, which often reads badly in Arabic, Japanese, or German.

Plurals

Many languages have more than two plural forms. Use <plurals> to handle them correctly:

<!-- res/values/strings.xml --> <plurals name="unread_messages"> <item quantity="one">You have %1$d unread message.</item> <item quantity="other">You have %1$d unread messages.</item> </plurals>
int count = 3; String msg = getResources().getQuantityString( R.plurals.unread_messages, count, count); // "You have 3 unread messages."

Colors

Colors belong in res/values/colors.xml as ARGB or RGB hex literals:

<!-- res/values/colors.xml --> <resources> <color name="brand_primary">#1A73E8</color> <color name="brand_primary_dark">#1558B0</color> <color name="surface">#FFFFFF</color> <color name="on_surface">#1C1B1F</color> <color name="error">#B3261E</color> </resources>

Use colors in layout XML with @color/:

<TextView android:textColor="@color/on_surface" android:background="@color/surface" ... />

Resolve a color in Java with ContextCompat.getColor():

import androidx.core.content.ContextCompat; int brandColor = ContextCompat.getColor(this, R.color.brand_primary); myView.setBackgroundColor(brandColor);
Do not call getResources().getColor(int) directly. It was deprecated in API 23 because it ignores the current theme. Always use ContextCompat.getColor(context, R.color.xxx), which is safe on all API levels and respects themes correctly.

Dimensions

Dimensions are stored in res/values/dimens.xml. Android uses two units you must know:

  • dp (density-independent pixel) — use for all layout sizes (margins, padding, widths, heights). 1 dp = 1 physical pixel on a 160 dpi screen; the system scales automatically on higher-density displays.
  • sp (scale-independent pixel) — use exclusively for text sizes. Like dp but also scales with the user's system font-size preference. Never set textSize in dp.
<!-- res/values/dimens.xml --> <resources> <dimen name="screen_margin">16dp</dimen> <dimen name="card_corner_radius">12dp</dimen> <dimen name="button_height">48dp</dimen> <dimen name="text_body">14sp</dimen> <dimen name="text_headline">24sp</dimen> </resources>

Apply dimensions in XML:

<Button android:layout_width="match_parent" android:layout_height="@dimen/button_height" android:layout_margin="@dimen/screen_margin" android:textSize="@dimen/text_body" />

Read a dimension in Java (returns pixels, already scaled for the current display):

float marginPx = getResources().getDimension(R.dimen.screen_margin); // Use TypedValue to convert dp to px manually when needed: float dp = 16f; float px = TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());

Accessing Resources — The R Class

Every time you build, the Android Gradle plugin generates R.java (or an equivalent binary artifact). It contains nested static classes — R.string, R.color, R.dimen, R.id, R.layout, and so on — each holding integer constants that map to the actual resource. You never construct or mutate this class; you only read from it.

// All of these compile to integer lookups at runtime: R.string.app_name // an int R.color.brand_primary // an int R.dimen.screen_margin // an int
If Android Studio shows "Cannot resolve symbol R" after adding a new resource, it usually means the XML is malformed (a typo in a tag name or a missing closing element). Fix the XML and rebuild — Build > Make Project. The R class is regenerated on every successful build.

Localization: Providing Alternative Strings

To translate strings into Arabic, create res/values-ar/strings.xml and provide only the strings that differ. You do not need to duplicate every string — only override what changes:

<!-- res/values-ar/strings.xml --> <resources> <string name="app_name">تطبيقي</string> <string name="welcome_message">أهلاً بك، %1$s!</string> <string name="login_button">تسجيل الدخول</string> </resources>

When the device locale is Arabic, getString(R.string.login_button) automatically returns "تسجيل الدخول" without any code change whatsoever. This is the entire value proposition of the resource system.

Summary

Resource files are not a formality — they are the mechanism by which your app becomes correct on every device, locale, and theme without branching logic in Java. Keep all user-visible strings in strings.xml, all colors in colors.xml, and all layout measurements in dimens.xml. Reference them with @string/, @color/, @dimen/ in XML and with the R class in Java. In the next lesson you will use Intents to navigate between two Activities — and the labels and colors you define here will travel with you.