Android Application Development For Dummies, 3rd Edition (2015)
Part II. Building and Publishing Your First Application
Chapter 6. Understanding Android Resources
In This Chapter
Knowing why resources are important in Android
Working with image resources
Resources are mentioned in detail throughout this book, so you might wonder why an entire chapter is devoted to them. Discussing resources and their use in Chapters 3 and 4 is necessary to help you understand the basic structure of the resource directory and the use of resources to build a simple application. One compelling reason to use resources in your application — localization — is covered in this chapter.
Resources are additional static content that are an intrinsic part of your app but aren’t part of your Java code. The most common resources are
Earlier chapters in this book introduce you to layouts, strings, and images because they’re the most common types of resources that you use in everyday Android application development. The remaining resources may need some explanation, so the following few sections will clear them up.
In an Android resource, a dimension is a number followed by a unit of measurement, such as 10px, 2.5in, or 5sp. You use a dimension when specifying any property in Android that requires a numeric unit of measure. For example, you may want the padding of a layout to be 10px. Android supports the following units of measure:
· density‐independent pixel (dp or dip): This is the most commonly used dimension. Dp is based on the physical density of the screen. These units are relative to a screen measuring 160 dots per inch (dpi); therefore, 1 dp is equivalent to 1 pixel on a 160‐dpi screen. The ratio of dp to pixels changes with screen density, but not necessarily in proportion.
The dp concept is complex; you will want to support multiple screen densities, so check out the “Supporting Multiple Screens” article at http://d.android.com/guide/practices/screens_support.html.
· scale‐independent pixel (sp or sip): This unit resembles the dp unit but is scaled according to the user’s font‐size preference. Use sp dimensions when specifying font sizes in your application.
· pixel (px): A pixel corresponds to a pixel on the screen. This unit of measure isn’t recommended for most cases. Your app may look great on a medium‐density device but look distorted and out of place on a high‐density screen (and vice versa) because the dpi differs.
· point (pt): A point is inch, based on the physical size of the screen. Like px, pt is not recommended.
· millimeter (mm): This unit is based on the size of the screen. Like px, mm is not recommended.
· inch (in): This unit is based on the physical size of the screen. Like px, in is not recommended.
Styles in Android are similar to Cascading Style Sheets (CSS) in the web development realm: You use styles to (you guessed it) style an application. A style is a collection of properties that can be applied to an individual view (within the layout file) or to an activity or to your entire application (from within the manifest file). Styles support inheritance, so you can provide a basic style and then modify it for each particular use case in your application. Style property attribute examples include text size, text color, and background.
A theme is a style applied to an entire activity or application, rather than an individual view. When a style is applied as a theme, every view in the activity and/or application inherits the style settings. For example, you can set all TextView views to a particular font, and all views in the themed activity or application then display their text in that font.
The value resource can contain many different types of value type resources for your application, including
· Bool: A Boolean value defined in XML whose value is stored in an arbitrary filename in the res/values/ <filename> .xml file, where <filename> is the name of the file. An example is bools.xml.
· Integer: An integer value defined in XML whose value is stored with an arbitrary filename in the res/values/ <filename> .xml file. An example is integers.xml.
· Integer array: An array of integers defined in XML whose set of values is stored with an arbitrary name in the res/values/ <filename> .xml file, where <filename> is the name of the file. An example is integers.xml. You can reference and use these integers in your code to help define loops, lengths, and other elements.
· Typed array: An array used to create an array of resources, such as drawables. You can create arrays of mixed types. Therefore, the arrays aren’t required to be homogeneous — however, you must be aware of the data type so that you can appropriately cast it. As with other resources, the filename is arbitrary in the res/values/ <filename> .xml file. An example is types.xml.
Whether your app is using the action bar or a menu, Android treats them both the same and you’ll define them the same way. A menu can be defined via either code or XML. The preferred way to define one is via XML; therefore, the various menus you create should be placed into the menu/ directory. Each menu has its own .xml file.
The colors file, typically located in the values/colors.xml file, lets you name colors, such as login_screen_font_color. This might depict the color of the text you’re using on the logon page, for example. Each color is defined as a hexadecimal value.
Working with Resources
You may have worked with resources a few times in this book, and at this point you’re likely familiar with using the R class to access resources from within your application. If you’re rusty on resources and the generated R file, see Chapter 3.
Moving strings into resources
As you become an experienced programmer, you may start to take shortcuts to get your project built and working. Say that initially you forget to move strings into resources, and you have to come back at a later time to do it. You can extract a string into a resource using the built‐in tools.
The long way
Here’s one way to extract a string into a resource:
1. Create a new string resource.
2. Copy its name.
3. Replace the string value in your layout with the resource identifier.
This way is fine. It’s not a huge pain, but it does take a little time.
The fast way
You can cut the time to create a string resource to fewer than 15 seconds. If you do this 30 times a day (which is feasible in an 8‐hour day), you can save 15 minutes of just copying and pasting. That’s five hours a month doing the copy‐and‐paste dance!
Follow these steps:
1. In Android Studio, open a random layout file such as activity_main.xml in the layouts directory.
2. Add a new TextView element that looks like the following:
android:text="I need a kombucha refill, please"/>
3. Place your cursor on the boldface line with the hardcoded text string and press Alt+Enter.
A menu opens with various options.
4. Choose the Extract String Resource option.
The Extract String Resource dialog box opens, as shown in Figure 6-1, and you can set various options for the resource.
5. Choose a name for your resource such as kombucha_refill, leave the other options set to their defaults, and click OK.
You can now see that the layout file has been modified. The text "I need a kombucha refill, please" has been replaced with "@string/kombucha_refill".
If you open the strings.xml file in the res/values folder, you can see your new string resource.
Figure 6‐1: The Extract Android String dialog box.
That’s pretty cool! You can see that doing this 20 or 30 times a day can add up and save you a lot of time.
Wrestling the image beast
One of the most difficult parts about resources can be images. They might look great on medium‐density devices but look like garbage on high‐density devices. This is where multiple‐density folders come into play. These density‐specific drawable folders are explained inChapter 3.
Battling pixelation and compression
The issue you’ll most likely encounter is pixelation and compression/expansion (moving from higher‐ to lower‐density devices and vice versa). To work around this issue, design your graphics at a high density, such as 640 dpi in large‐size format. For example, if you’re building the launcher icon, build it at 512px high and 512px wide to upload to Google Play. Although the xxxhdpi folder might need an image of only 192px high x 192px wide (the largest in use), it doesn’t mean that in two or three months a higher resolution device won’t be released.
This situation can be painful because working with large image files in image editing programs is difficult if you don’t have a computer with decent capabilities. But you have to trust us on this one: Having a large raw‐image file that’s high density is much easier to mold and shape into the correct densities you’ll need.
Downsizing a high‐resolution image doesn’t distort its quality (other than losing its fine edges and detail), but upscaling does because it creates pixelation. Starting with a large file reduces the chance that you’ll ever have to upscale, which means that your app graphics will always look crisp. If possible, working with vector files will make this even easier.
If you’re creating graphics in an image editing tool that supports layers, place each item in your graphic on a different layer. The reasons are many, but here are the key factors:
· Changes: At some point, you will need to change something in your graphic — its background, font, or logo, for example. If you have all these items in different layers, you can make the change without affecting the rest of the graphic.
· Localization: An example from an earlier section in this chapter talks about various strings in different languages, and graphics are no different. Many times as you develop applications, you will encounter graphics with stylized text in the graphic itself. If your application is being translated into Japanese and your graphics contain stylized English text, you can create a Japanese version of those graphics and place them in a Japanese drawable region folder, such as res/drawable‐ja. The Android platform recognizes which region it’s in (in this case, Japan). If the region’s resource folders (res/drawable‐ja, res/values‐ja, and so on) are available, Android uses them in the application. That being said, it’s always easier to keep your text in text resources and your images in image resources. Translating text resources is easier than making new copies of your images for every new language.
Making your apps global with resources
The Android platform surpassed the Apple iPhone in U.S. market share in the first quarter of 2010. Now carriers around the world are developing Android‐based smartphones, which simply means more potential users for your apps.
What this statement means to you as a developer is that Android is a huge market with tons of opportunity waiting to be tapped. Though this opportunity is exciting, taking the greatest advantage of it requires that you understand resources and how they affect the usability of your apps. For example, if a user in the United States uses your app and it was written for an English‐speaking audience (using resources or not), the user can use it. However, if you hard‐code all your string values into your views and activities and then need to release a Chinese version, you have to rewrite your application to use resources. When you use resources, you can have a translator translate your strings and drawables into the region you’re targeting — such as China.
Resources allow you to extract human‐readable strings, images, and viewable layouts into resources that you can reference. You can create various resource folders to handle screens of differing sizes, languages (strings and drawables), and layout options, such as landscape and portrait. Landscape and portrait layouts come into play when a user rotates the device 90 degrees in either direction.
If you want your apps to be available on as many Android devices as possible around the world, you should use resources at all times. Always put all strings into the strings.xml file because, someday, someone from another country will want your application in another language. To transport your application to another language, you simply need a translator to translate your strings.xml file into her language, and then you can create various values folders to hold the appropriate region’s values. Android takes care of the hard work. For example, if the user is in China and his phone is set to the Chinese Locale, Android looks for the values folder named values‐cn, which is where Chinese values are stored — including the Chinese version of the strings.xml file. If Android cannot find such a folder, the platform defaults to the values folder, which contains the English version of the strings.xml file. (For more on strings, see the section, “Moving strings into resources,” earlier in this chapter.)
When it comes down to it, having a translator update your strings and creating a new folder with the new strings.xml file located within are simple tasks. Expand this concept to other languages and tablets and televisions and you can see the potential. You’re no longer looking at mobile users as your target audience. You’re looking at Android users, and with the options being released, you could be looking at billions of users. Using resources correctly can make your expansion into foreign markets that much easier.
Looking to have your app translated? You have a few options. Visit http://translate.google.com/toolkit to learn how to upload your strings.xml file and have it automatically translated by a computer. For higher quality results, you should look athttp://d.android.com/distribute/tools/localization‐checklist.html to learn how to upload your app and have it translated by a professional translator.
Designing your application for various regions is a big topic. You can find more in‐depth information in the “Localizing with Resources” article of the SDK documentation at http://d.android.com/guide/topics/resources/localization.html.
You’re not forced into releasing your application to all countries at once — Google Play will allow you to release your app only to specific countries. Therefore, if you have written an application for the Berlin bus route system in Germany, it probably doesn’t make sense to have a Chinese version, unless you want to cater to Chinese tourists as well as to German residents.
Different Strokes for Different Folks: Using Resource Qualifier Directories
As discussed in Chapter 3, you can use different drawable directories to create different resources for higher and lower resolution devices. This is an example of using resource qualifiers, and it turns out that you can use the same trick to do many other things.
Using default resources
By default, when you place a resource into your drawable, layout, menu, value, or other directory in the res folder, you’re supplying a default resource. This is the resource that will be used if no other resources are specified. You’ve done this already with drawables, layouts, and strings.
These default resources will be used if there are no other specific resources overriding them. To override a resource for special cases, you create files in directories that have special names. The next sections will go over some common ways you might want to override resources.
Localizing to another language
Let’s say that you want to translate the Silent Mode Toggle app into Spanish. As covered in Chapter 3, you can do that by creating a values‐es directory, and placing a new strings.xml file into that directory that “overrides” the default values that are invalues/strings.xml. Whenever your app is opened on a device that is set to use Spanish as the default language, your app automatically displays the strings from values‐es/strings.xml rather than the default English values.
This works with any of Android’s supported languages, not just Spanish. You can use fr for French, de for German, and so on.
In addition, Android allows you to subdivide languages by region. So you can provide Portuguese translations for Portugal in values‐pt, and in values‐pt‐rBR for Brazil (which also speaks Portuguese).
Visit http://developer.android.com/guide/topics/resources/localization.html for more information about how to localize your app to different languages and regions.
You don’t necessarily need to override every value in your strings.xml files. For example, if you have a values/strings.xml using U.S. English and a values‐en‐rGB/strings.xml for U.K. English, you only need to supply translations for those few things that mean different things in the U.S. and the U.K. (such as pants).
But be careful if you supply selective translations! The above might make sense for U.S. and U.K. English, but it does not make sense for a French translation file. If you provide only some French translations, then some of your app will be in English and some in French!
Handling different screen sizes
Resource qualifier directories can be a key tool in your battle to handle the hundreds of different screen sizes and resolutions out there in the Android world.
There are two main techniques you will want to use: selecting resources based on screen density or based on screen size.
Screen density (pixel density)
Android devices come in many different pixel densities. Older phones came in mdpi‐ or ldpi‐pixel densities. These days, most newer phones come in hdpi‐or‐above pixel densities. But some tablets may still come in mdpi densities. Here is the list of densities Android supports:
· ldpi (low): ~120 dpi (dots per inch)
· mdpi (medium): ~160 dpi
· hdpi (high): ~240 dpi
· xhdpi (extra‐high): ~320 dpi
· xxhdpi (extra‐extra‐high): ~480 dpi
· xxxhdpi (extra‐extra‐extra‐high): ~640 dpi
As described in Chapter 3, you can use these densities as qualifiers in your drawables directory to provide different images for different density screens. For example, you can provide different sizes of assets for different devices by putting the image files in drawables‐mdpi,drawables‐xxhdpi, and so on.
In addition, you can use them as qualifiers on your values directories to utilize slightly different values for things like margin, padding, and text size on different sized devices. These values are typically put into a dimens.xml file in the corresponding values directory.
Remember, you do not necessarily have to provide all your images for all densities. A good rule of thumb is to provide the xxhdpi assets for all your images and rely on Android to automatically scale them down to the other sizes as necessary. But if there are some images that don’t look great when scaled down (such as a company’s logo for example), you may want to provide that asset at all densities.
You may want to use different layouts for different sized screens. For example, a tablet has much more screen real estate than a phone, so you will likely want to lay out some of your screens differently on a tablet than on a phone.
Android provides the smallestWidth qualifier to help you distinguish between a phone and tablet. “Smallest width” means the smaller of your height of width, regardless of which orientation your device is in. So if your phone is 600dp x 800dp, the smallest width would be 600.
This is very handy for distinguishing between phones and tablets. In general, the common consensus is that a smallest width of 600dp or more is a tablet, whereas anything less is a phone.
The way to use the smallestWidth qualifier is to provide your default phone layouts in res/layouts, and then put any tablet‐only layouts that you need in res/layouts‐sw600dp. Android will then pick the correct layout file depending on whether the user is using a phone or a tablet.
See Part IV for more information about how to use different layouts for tablets versus phones.
Portrait versus landscape orientations
Similarly, you may want to provide a different layout if the phone is in portrait mode or landscape mode. This can be handy for showing multi‐pane layouts when in landscape mode, but collapsing them to a single pane when in portrait.
Put all your default layouts into res/layout. These are used regardless of which orientation your phone is in. If you want to have landscape‐only layouts, put them in res/layout‐land. Similarly, portrait‐only layouts should go in res/layout‐port.
Handling old Android versions
You can also use resource qualifiers to supply alternate resources for when your app is running on different versions of Android. For example, older versions of Android use different styles and colors, so perhaps you want your app to use a slightly different color when running on Android 4.1 rather than Android 5.0.
To do this, you can put your regular colors in res/values/colors.xml, and then put your Android 4.1 colors into res/values‐v16/colors.xml (for platform level 16, or Android 4.1).
See Chapter 17 for more information about backward compatibility and handling older versions of Android.
Qualifier name rules
Now that you know the basics, there are some additional things that can be helpful to know about using resource qualifiers:
· You can specify multiple qualifiers for a single set of resources, separated by dashes. For example, drawable‐en‐rUS‐land applies to US‐English devices in landscape orientation.
· If you use multiple qualifiers, they must be in a special order that you can find here: http://d.android.com/guide/topics/resources/providing‐resources.html#table2. For example:
· Wrong: drawable‐hdpi‐port/
· Correct: drawable‐port‐hdpi/
· Only one value for each qualifier type is supported. For example, if you want to use the same drawable files for Spain and France, you cannot have a directory named drawable‐rES‐rFR.
There are many other things you can customize by using resource qualifiers! Visit http://d.android.com/guide/topics/resources/ for more information.