The following is the first few sections of a chapter from The Busy Coder's Guide to Android Development, plus headings for the remaining major sections, to give you an idea about the content of the chapter.


Some Words About Resources

It is quite likely that by this point in time, you are “chomping at the bit” to get into actually writing some code. This is understandable. That being said, before we dive into the Java source code for our stub project, we really should chat briefly about resources.

Resources are static bits of information held outside the Java source code. Resources are stored as files under the res/ directory in your Android project layout (whether that is in the project root for Eclipse or in the main/ sourceset for Android Studio). Here is where you will find all your icons and other images, your externalized strings for internationalization, and more.

These are separate from the Java source code not only because they are different in format. They are separate because you can have multiple definitions of a resource, to use in different circumstances. For example, with internationalization, you will have strings for different languages. Your Java code will be able to remain largely oblivious to this, as Android will choose the right resource to use, from all candidates, in a given circumstance (e.g., choose the Spanish string if the device’s locale is set to Spanish).

We will cover all the details of these resource sets later in the book. Right now, we need to discuss the resources in use by our stub project, plus one more.

This chapter will refer to the res/ directory. Android Studio users will find that in the app/src/main/ directory of their project.

String Theory

Keeping your labels and other bits of text outside the main source code of your application is generally considered to be a very good idea. In particular, it helps with internationalization (I18N) and localization (L10N). Even if you are not going to translate your strings to other languages, it is easier to make corrections if all the strings are in one spot instead of scattered throughout your source code.

Plain Strings

Generally speaking, all you need to do is have an XML file in the res/values directory (typically named res/values/strings.xml), with a resources root element, and one child string element for each string you wish to encode as a resource. The string element takes a name attribute, which is the unique name for this string, and a single text element containing the text of the string:

<resources>
  <string name="quick">The quick brown fox...</string>
  <string name="laughs">He who laughs last...</string>
</resources>

One tricky part is if the string value contains a quote or an apostrophe. In those cases, you will want to escape those values, by preceding them with a backslash (e.g., These are the times that try men\'s souls). Or, if it is just an apostrophe, you could enclose the value in quotes (e.g., "These are the times that try men's souls.").

For example, a project’s strings.xml file could look like this:

<resources>
  <string name="app_name">EmPubLite</string>
</resources>

We can reference these string resources from various locations, in our Java source code and elsewhere. For example, the app_name string resource often is used in the AndroidManifest.xml file:

<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.commonsware.empublite"
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools">

  <supports-screens
    android:largeScreens="true"
    android:normalScreens="true"
    android:smallScreens="false"
    android:xlargeScreens="true" />

  <application
    android:allowBackup="false"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme"
    tools:ignore="GoogleAppIndexingWarning">
    <activity android:name=".EmPubLiteActivity">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
  </application>

</manifest>

Here, the android:label attribute of the <application> element refers to the app_name string resource. This will appear in a few places in the application, notably in the list of installed applications in Settings. So, if you wish to change how your application’s name appears in these places, simply adjust the app_name string resource to suit.

The syntax @string/app_name tells Android “find the string resource named app_name”. This causes Android to scan the appropriate strings.xml file (or any other file containing string resources in your res/values/ directory) to try to find app_name.

Um, Wait, My Manifest Does Not Look Like That

When you view a manifest like that in Android Studio, it may appear as though you are not using resources, as you may not see @string/... references:

AndroidManifest.xml, As Initially Viewed in Android Studio
Figure 53: AndroidManifest.xml, As Initially Viewed in Android Studio

Here, android:label looks as though it is the hard-coded value “EmPubLite”.

However, notice that the attribute value is formatted differently than the others. The rest are green text with a white background, while this one is gray text with a shaded background.

That is because Android Studio is lying to you.

If you hover your mouse over the value, you will see the real attribute appear just below it:

AndroidManifest.xml, With Mouse Hovering Over EmPubLite
Figure 54: AndroidManifest.xml, With Mouse Hovering Over “EmPubLite”

And, if you click on the fake value, you will see the real XML, with the real string resource value.

What is happening is that Android Studio, by default, will substitute a candidate value for the resource in its presentation of the manifest, other resources that refer to resources, and even Java code. Any time you see that gray-on-light-blue formatting, remember that this is not the real value, and that you have to uncover the real value via hovering over it or clicking on it.

Styled Text

Many things in Android can display rich text, where the text has been formatted using some lightweight HTML markup: <b>, <i>, and <u>. Your string resources support this, simply by using the HTML tags as you would in a Web page:

<resources>
  <string name="b">This has <b>bold</b> in it.</string>
  <string name="i">Whereas this has <i>italics</i>!</string>
</resources>

CDATA. CDATA Run. Run, DATA, Run.

Since a strings resource XML file is an XML file, if your message contains <, >, or & characters (other than the formatting tags listed above), you will need to use a CDATA section:

<string name="report_body">
<![CDATA[
<html>
<body>
<h1>TPS Report for: {{reportDate}}</h1>
<p>Here are the contents of the TPS report:</p>
<p>{{message}}</p>
<p>If you have any questions regarding this report, please
do <b>not</b> ask Mark Murphy.</p>
</body>    
</html>
]]>
  </string>

The Directory Name

Our string resources in our stub project are in the res/values/strings.xml file. Since this directory name (values) has no suffixes, the string resources in that directory will be valid for any sort of situation, including any locale for the device. We will need additional directories, with distinct strings.xml files, to support other languages. We will cover how to do that later in this book.

Editing String Resources

If you double-click on a string resource file, like res/values/strings.xml, in Android Studio, you are presented the XML and edit it that way. There is an option for entering a dedicated string translation view, covered later in this book.

Multi-Locale Support

Android 7.0 users can indicate that they support more than one language:

Android 7.0 Language Settings
Figure 55: Android 7.0 Language Settings

The user can choose the relative priorities of these languages, by grabbing the handle on the right side of the row and dragging the language higher or lower in the list.

This has impacts on resource resolution for any locale-dependent resources, such as strings. Now Android will check multiple languages for resource matches, before falling back to the default language (e.g., whatever you have in res/values/strings.xml). Hence, it is important that you ensure that you have a complete set of strings for every language that you support, lest the user perhaps wind up with a mixed set of languages in the UI.

You can find out what languages the user has requested via a LocaleList class and its getDefault() static method. This, as the name suggests, has a list of Locale objects representing the user’s preferred languages. If you had previously been using Locale alone for this (e.g., for specialized in-app language assistance beyond resources), you will want to switch to LocaleList for Android 7.0 and beyond.

Got the Picture?

Android supports images in the PNG, JPEG, and GIF formats. GIF is officially discouraged, however; PNG is the overall preferred format. Android also supports some proprietary XML-based image formats, though we will not discuss those at length until later in the book. Many newer versions of Android also support Google’s WebP image format, though this is not especially popular.

There are two types of resources that use images like these: drawables and mipmaps. In truth, they are nearly identical. Mipmaps are used mostly for “launcher icons” — the icons seen in home screen launchers that identify activities that the user can start. Drawables hold everything else.

(if you are a seasoned Android developer and are reading this section: while drawable resources might be removed when packaging an APK, such as for the Gradle for Android split system for making density-specific editions of an app, mipmap resources are left alone, apparently)

It is possible to have res/drawable/ and res/mipmap/ directories in an Android module. However, you will not find bitmaps there usually. Instead, those reside in directories like res/drawable-mdpi/ and res/drawable-hdpi/.

These refer to distinct resource sets. The suffixes (e.g., -mdpi, -hdpi) are filters, indicating under what circumstances the images stored in those directories should be used. Specifically, -ldpi indicates images that should be used on devices with low-density screens (around 120 dots-per-inch, or “dpi”). The -mdpi suffix indicates resources for medium-density screens (around 160dpi), -hdpi indicates resources for high-density screens (around 240dpi). -xhdpi indicates resources for extra-high-density screens (around 320dpi), -xxhdpi indicates extra-extra-high-density screens (around 480dpi), -xxxhdpi indicates extra-extra-extra-high-density screens (around 640dpi), and so on.

In the EmPubLite tutorial project, you will find a series of mipmap directories with the same sorts of suffixes (e.g., res/mipmap-hdpi). Inside each of those directories, you will see an ic_launcher.png file. This is the stock icon that will be used for your application in the home screen launcher. Each of the images is of the same icon, but the higher-density icons have more pixels. The objective is for the image to be roughly the same physical size on every device, using higher densities to have more detailed images.

Our AndroidManifest.xml file then references our ic_launcher icon in the <application> element:

<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.commonsware.empublite"
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools">

  <supports-screens
    android:largeScreens="true"
    android:normalScreens="true"
    android:smallScreens="false"
    android:xlargeScreens="true" />

  <application
    android:allowBackup="false"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme"
    tools:ignore="GoogleAppIndexingWarning">
    <activity android:name=".EmPubLiteActivity">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
  </application>

</manifest>

Note that the manifest simply refers to @mipmap/ic_launcher, telling Android to find a mipmap resource named ic_launcher. The resource reference does not indicate the file type of the resource — there is no .png in the resource identifier. This means you cannot have ic_launcher.png and ic_launcher.jpg in the same project, as they would both be identified by the same identifier. You will need to keep the “base name” (filename sans extension) distinct for all of your images.

Also, the @mipmap/ic_launcher reference does not mention what screen density to use. That is because Android will choose the right screen density to use, based upon the device that is running your app. You do not have to worry about it explicitly, beyond having multiple copies of your icon. If Android detects that the device has a screen density for which you lack an icon, Android will take the next-closest one and scale it.

Getting Android Drawables

You may be a graphic designer. Or, you may know a graphic designer. In those cases, you can create your own icons, ideally following Google’s design guidelines for iconography.

If you are not a graphic designer and do not have ready access to one, you will need to come up with your drawable resources by other means. There are plenty of icon libraries available from third parties, but the following sections outline some of Google’s solutions for putting icons in your app.

Android Image Asset Wizard

Android Studio offers an Image Asset Wizard. This wizard is designed to take a starter image and give you icons, in a variety of densities, that use that image for a particular image role, such as your home screen launcher icon (the ic_launcher.png file we saw earlier in this chapter). The Image Asset Wizard will give you mipmap resources if you choose to create launcher icons, and it will give you drawable resources if you choose to create other sorts of icons.

There is also a separate Vector Asset Wizard, discussed later in this book.

Android Asset Studio

The same basic functionality found in the Image Asset Wizard is available outside any IDE (but inside a Chrome browser) in the form of the Android Asset Studio. As with the Image Asset Wizard, you can choose a type of icon (e.g., launcher icons):

Android Asset Studio, Launcher Icon Page
Figure 56: Android Asset Studio, Launcher Icon Page

Then you can specify the source of the base image (uploaded file, canned clipart, or free-form text) and other configuration data. The resulting images, in various densities, can be downloaded at the bottom of the page:

Android Asset Studio, Launcher Icon Page, with Icons
Figure 57: Android Asset Studio, Launcher Icon Page, with Icons

Editing Existing Drawable Resources

Android Studio does not ship with any sort of image editor that you could use for PNG and JPEG files. Hence, you will find yourself editing these images using other tools outside of your IDE, or finding some IntelliJ plugin that perhaps can serve in that role.

WebP

Android 4.0 added partial support for Google’s WebP image format, and Android 4.3 devices support the previously-missing features (lossless compression and transparency). WebP serves as a replacement for both PNG and JPEG, and in some circumstances it can result in smaller on-disk sizes for near-equivalent image quality.

Android Studio, starting with version 2.3, has special support to help you convert drawable resources and other images from JPEG and PNG to WebP. Simply right-click over the image in the project tree and choose “Convert to WebP” from the context menu.

Initially, you are given a window for controlling the quality and output:

WebP Converter in Android Studio
Figure 58: WebP Converter in Android Studio

“Lossy encoding” refers to the type performed by JPEG, taking into account that humans have limited ability to distinguish similar colors to achieve tighter compression. “Lossless encoding” refers to the type performed by PNG, where the compressed image is identical to the original, just as a ZIP file’s contents are identical to the files before they were ZIPped. For lossy encoding, you can choose a quality percentage, where higher quality images will not compress as well.

You can also:

If you choose lossy compression and leave the “preview” checkbox checked, you are then presented with a window showing the results of the conversion at your requested quality level:

WebP Conversion Preview
Figure 59: WebP Conversion Preview

You can adjust the quality slider below the images to see how the image changes with different quality levels and how much additional disk savings you will get from the WebP conversion.

When you are done, the WebP converter will replace your old PNG or JPEG file with the converted WebP image.

Round Application Icons

On some Android 7.1+ devices, the home screen launcher can show round icons:

Pixel Launcher on Google Pixel, Running Android 7.1
Figure 60: Pixel Launcher on Google Pixel, Running Android 7.1

By default, this will not happen — these devices will show the same launcher icon as will be used on any other device. That comes from the android:icon attribute in the <application> element of your manifest.

However, if you want, you can add an android:roundIcon attribute, pointing to a separate mipmap resource, set up in the style used by Google’s apps.

The Image Asset Wizard has a “Shape” drop-down when working with launcher icons. Choosing “Circle” will set up the standard circle background for you:

Image Asset Wizard, with Circle Shape Selected
Figure 61: Image Asset Wizard, with Circle Shape Selected

On Android 7.0 and older devices — and even on some Android 7.1+ devices, apparently — the android:roundIcon attribute will be ignored. But, for some devices, it will be used. Whether you bother with this is up to you.

Dimensions

The preview of this section was traded for a bag of magic beans.

The Resource That Shall Not Be Named… Yet

The preview of this section was eaten by a grue.