R.java
R.java is neat. R.java is elegant. Due to its subversiveness (in a good way) its makings are implicit. It is fun to learn about Android.R.
At a mile high level, every application has resouces. Familiar example of resources are strings, colors, and bitmaps. Instead of hard coding strings in an application one will use an id for a string.
Let's start with strings and see how they are used.
Create a file called "/res/values/srings.xml"
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">hello</string>
<string name="app_name">hello appname</string>
</resources>
This file will automatically update a "java" class in your root package called R.java
package com.ai.android.helloworld;
public final class R {
public static final class attr {
}
public static final class drawable {
public static final int icon=0x7f020000;
}
public static final class id {
public static final int b1=0x7f050001;
public static final int text1=0x7f050000;
}
public static final class layout {
public static final int main=0x7f030000;
}
public static final class string {
public static final int app_name=0x7f040001;
public static final int app_name1=0x7f040003;
public static final int hello=0x7f040000;
public static final int hello1=0x7f040002;
}
}
For now focus on the static definition for "static final class string". You will see two final static "int's" defined with "hello" and "app_name".
we could have used these any where in the source code using the structure
R.string.hello
But interestingly this is an "int" and not a "String". Most methods that take strings also take these resource identifiers.
Some of these conventions are reserved and some are not. For example it is just a convention that most sample applications define all strings in one file "strings.xml". But Android takes any number of arbitrary files as long as the structure of the xml file is as follows
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">hello</string>
<string name="app_name">hello appname</string>
</resources>
So before copying the R.java here for a demonstration, I have placed another file called strings1.xml that has the following entries
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello1">hello</string>
<string name="app_name1">hello appname</string>
</resources>
Eclipse android plugin will validate the uniqueness of these ids at compile time.
This pattern applies to all the files that are in the "values" sub directory.
It is important that the files are placed under "res/values" sub directory. All string resources identified by the element "string" are collected into a single java name space called R.string.
Layout Resources
Let us take a look at the next resource that is most often used. Take a look at the following code in He
public class HelloWorldActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView tv = (TextView)this.findViewById(R.id.text1);
tv.setText("Try this text instead");
}
This code here demonstrates a few important things about resources and R.java. The following line
setContentView(R.layout.main)
is pointing out that there is static class by the name of "layout" and there is a constant in there called "main" (an integer) pointing to a "View" defined by an xml file. This statement would expect the following file to be there
"/res/layout/main.xml"
However it is still a bit of mystery around what is
R.id.text1
What are "ids?" you could ask.
So let us untangle this thread by looking at the "main.xml"
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:id="@+id/text1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<Button
android:id="@+id/b1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@+string/hello"
/>
</LinearLayout>
Files of this kind defines "Views" or "Pages" or "Layouts" for applications. In this case this file here lays out two controls or "views": a TextView and a "Button" in a top down fashion (because of vertical LinearLayout).
Each file in the "res/layout" sub directory generates a unique constant unlike string resources where irrespective of the number of files what matters is how many individual string resources are inside. In the case of layouts it is the number of files. For example if I have two files under "res/layout" called "file1.xml" and "file2.xml" then I will have the following entries in R.java
public static final class layout {
.... any other files
public static final int file1=0x7f030000;
public static final int file2=0x7f030001;
}
The views that are defined in these layout files can be accessed in code by referencing their ids from R.java file. Here is an example:
TextView tv = (TextView)this.findViewById(R.id.text1);
tv.setText("Try this text instead");
In this example the TextView is located by using the findViewById method of the Activity class. The constant R.id.text1 corresponds to the id defined for the TextView. The "id" for the TextView in the layout file is
<TextView android:id="@+id/text1"
..
</TextView>
The attribute value for attribute "id" is indicating that a constant called "text1" will be usd to uniquely identify this view among other views hosted by that activity. The id "text1" will be created if it doesn't exist already.
Resource Reference Syntax
The attribute syntax above "@+id/text1" is called a resource reference. It has the following formal structure
@[package:]type/name
The "type" will be one of the resource types availabe in R.java. It is worth reviewing what these are
drawable
id
layout
string
attr
"name" is the name given to the resource and also gets represented as an "int" constant in R.java. Now we come to the most important part of this syntax: The "package".
If you dont specify any package then the pair "type/name" will be resolved based on local resources and local R.java of this application or more precisely package.
If you say "android:type/name" then it will look in the package identified by "android" to be more precise "android.R.java" file. By that logic it is conceivable that you can use any java package name in its place to locate the right R.java to resolve the reference.
Based on this let us analyze a examples
<TextView id="text">
// Compile error, as id will not take raw text strings
<TextView id="@text">
// wrong syntax. It is missing a type name
// you will get an error "No resource type specified
<TextView id="@id/text">
//Error: No resource found that matches id "text"
<TextView id="@android:id/text">
// Error: Resource is not public
// indicating that there is no such id in android.R.id
<TextView id="@+id/text">
//Success: Creates an id called "text" in the local package
Defining your own ids
The following code segment
<TextView id="@+id/text">
indicates that (as pointed out) an id by name "text" is going to be used if one already exists. If it doesn't then a new one is going to be created. So when would an id like "text" might already exist in R.java for that to be reused.
One might be inclined to put a constant like "R.id.text" in R.java. But R.java is not editable, even if it were it gets regenerated all the time.
However there is a resource tag called
<resources>
<item type="id" name="text"/>
</resources>
The "type" refers to the type of resource in this case an "id". Once this id is in place then the following View definition would work
<TextView android:id="@id/text">
..
</TextView>
A Recap of Android resources
Every Android programmer is first exposed to Resources through R.java and most likely to use String and Layout resources. Android supports many other types of resources. It is worth while to understand the general nature of these resources before enumerating each one of them in detail.
Android supports XML files, bitmap files for images, and raw files (examples of which could include audio and video). With in the set of XML files there are two type. One kind of XMLs gets compiled into binary format and the other set just gets copied as they are.
Here are some important sub directories in the "res" folder
anim - compiled animation files
drawable - bitmaps
layout - ui/view definitions
values - arrays, colors, dimens, strings, styles
xml - compiled arbitrary raw xml files
raw - un compiled raw files
All these resources are compiled by "aapt" resource compiler and placed into the final "apk" file. "aapt" stands for Android Asset Packaging Tool. The tool that generates the final ZIP file of application assets. In addition to collecting raw assets together, it also parses resource definitions into binary asset data.
Color Resources
XML syntax
<resources>
<color name="opaque_red">#f00</color>
<color name="translucent_red">#80ff0000</color>
</resources>
Java code
int color = getResources.getColor(R.color.opaque_red);
Using colors in view definitions
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAlign="center"
android:textColor="@color/translucent_red"
android:text="Some Text"/>
String Resources
XML Syntax (use escape sequences)
<string name="good_example">"This'll work"</string>
<string name="good_example_2">This\'ll also work</string>
<string name="styled_welcome_message">We are <b><i>so</i></b> glad to see you.</string>
<string name="search_results_resultsTextFormat">
%1$d results for <b>"%2$s"</b>
</string>
Using it in java
// Assign a styled string resource to a TextView
// on the current screen.
CharSequence str = getString(R.string.styled_welcome_message);
TextView tv = (TextView)findViewByID(R.id.text);
tv.setText(str);
//using formatted strings
String resultsTextFormat = getContext().getResources().getString
(R.string.search_results_resultsTextFormat);
String resultsText = String.format(resultsTextFormat, count, escapedTitle);
CharSequence styledResults = Html.fromHtml(resultsText);
Using it in XML
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAlign="center"
android:text="@string/simple_welcome_message"/>
Dimension Resources
XML syntax
<resources>
<dimen name="one_pixel">1px</dimen>
<dimen name="double_density">2dp</dimen>
<dimen name="sixteen_sp">16sp</dimen>
</resources>
The units could be
px - pixels
in - inches
mm - millimeters
pt - points
dp - adjusts to screen density
sp - use it for fonts. allows user sizing
Java code
float dimen = Resources.getDimen(R.dimen.one_pixel);
Using it in XML
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="@dimen/sixteen_sp"/>
Image resources
Using images in XML
<ImageView id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:tint="#FF000000"
android:src="@drawable/chat_icon"/>
Color drawble Resources
These are color rectangles
XML definitions
<resources>
<drawable name="solid_red">#f00</drawable>
<drawable name="solid_blue">#0000ff</drawable>
<drawable name="solid_green">#f0f0</drawable>
</resources>
java code
// Assign a PaintDrawable as the background to
// a TextView on the current screen.
Drawable redDrawable = Resources.getDrawable(R.drawable.solid_red);
TextView tv = (TextView)findViewByID(R.id.text);
tv.setBackground(redDrawable);
xml code
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAlign="center"
android:background="@drawable/solid_red"/>
Stretchable images
<Button id="@+id/tiny"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerInParent="true"
android:text="Tiny"
android:textSize="8sp"
android:background="@drawable/my_button_background"/>
<Button id="@+id/big"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerInParent="true"
android:text="Biiiiiiig text!"
android:textSize="30sp"
android:background="@drawable/my_button_background"/>
Layout Resource oddities
Each xml node for an object supports both its own properties and also parents properties. The names of xml attributes for each class is documented in R.Stylable class.
The xml also supports attributes that look like "layout_abcAttrbitue". The word "layout" is reserved. It will get stripped off and the word after "_" (abcAttribute) is used to set the properties of the contained lay out object of a View.
Some examples
<?xml version="1.0" encoding="utf-8"?>
<!-- res/main_screen.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" // The object's own orientation property
android:padding="4" // Inherited View property
android:gravity="center" // The object's own property
android:layout_width="fill_parent" // Parent object's LinearLayout.LayoutParams.width
android:layout_height="fill_parent"> // Parent object's LinearLayout.LayoutParams.height
<TextView android:layout_width="fill_parent" // TextView.LayoutParams.width
android:layout_height="wrap_content" // TextView.LayoutParams.height
android:layout_weight="0" // TextView.LayoutParams.weight
android:paddingBottom="4" // TextView.paddingBottom
android:text="@string/redirect_getter"/> // TextView.text
<EditText id="@+id/text"
android:layout_width="fill_parent" // EditText.LayoutParams.width
android:layout_height="wrap_content" // EditText.LayoutParams.height
android:layout_weight="0" // EditText.LinearLayoutParams.weight
android:paddingBottom="4"> // EditText.paddingBottom
<requestFocus />
</EditText>
<Button id="@+id/apply"
android:layout_width="wrap_content" // Button.LayoutParams.width
android:layout_height="wrap_content" // Button.LayoutParams.height
android:text="@string/apply" /> // TextView.text
</LinearLayout>
Custom Layout Resources
tbd
Theme Resources
Themes are files in the "res/values" sub directory with the following structure
<style name=string [parent=string] >
<item name=string>Hex value | string value | reference</item>+
</style>
where parent is the parent theme. item is an attribute name, with a value that is a color value or a string or a resource. Here are some examples
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="SpecialText">
<item name="android:textSize">18sp</item>
<item name="android:textColor">#008</item>
</style>
<style name="ThemeNew">
<item name="windowFrame">@drawable/screen_frame</item>
<item name="windowBackground">@drawable/screen_background_white</item>
<item name="panelForegroundColor">#FF000000</item>
<item name="panelBackgroundColor">#FFFFFFFF</item>
<item name="panelTextColor">?panelForegroundColor</item>
<item name="panelTextSize">14</item>
<item name="menuItemTextColor">?panelTextColor</item>
<item name="menuItemTextSize">?panelTextSize</item>
</style>
</resources>
Here is how you can apply one of those styles
<!-- MainPageLayout.xml -->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:orientation="vertical"
android:scrollbars="vertical"
id="main_frame">
<EditText id="@+id/text1"
style="@style/SpecialText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Hello, World!" />
</LinearLayout>
Setting theme to an activity
setTheme(R.style.ThemeNew);
Here is how you apply theme in the manifest.xml
<!-- AndroidManifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.codelab.rssexample">
<activity class="AddRssItem"
android:label="@string/add_item_label"
android:theme="@android:style/Theme.Dialog"/>
</manifest>
Android.R
Just like R.java in a local package defines constants, Android has a set of constants for common resources that it defines. These constants can be seen at
http://code.google.com/android/reference/android/R.html
The defined constants cover the following resource types
anim
array
attr
color
dimen
drawable
id
layout
plurals
raw
sting
style
styleable
xml
A discussion on the structure of Android XML convention
If you notice the XML files in android closely you will that elements do not carry a namespace. But the attributes do carry a namespace caleld "android:". Usually elements carry a namespace in other xml parlance.
Consider the following TextView
<TextView
android:id="@+id/text1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>;
Android XML is there to facilitate specification of objects in XML and not there for the purity of XML. Primary goal is to go between objects and XML seamlessly. To this end some of the XML seems odd.
So the above XML is truly
<android.view.TextView
android:id="@+id/text1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>;
allowing an instantiation of class "android.view.TextView". We already have seen the explnation for the attribute value syntax starting with "@" or "@+".
The attributes need to be namespaced to allow
<?xml version=?1.0? encoding=?UTF-8??>
<com.me.myapp.MyTextView
xmlns:android=?http://schemas.android.com/apk/res/android?
xmlns:app=?http://schemas.android.com/apk/res/com.me.myapp?
android:layout_width=?fill_parent?
android:layout_height=?wrap_content?
android:text=?Hello World?
app:mySpecialFeature=?true?
/>
(Borrowed from notes from Diane Hackborn). Notice how MyTextView (having derived from TextView) specifies its own attributes through a name space of "app"
These XML documents are parsed at build time into a binary representation that is what is really read on the device. In addition to turning the XML structure into a binary format, android also does pre-processing such as assigning unique identifiers to attribute names based on their namespaces to avoid string comparisons, looking up attribute values like ?@string/mystring? to the resource identifier they are referencing, converting integer and color values like ?#fff? to 32-bit ints, stripping unnecessary things like comments, etc. So in a way you can look at the XML as our current way to generate the ?real? raw resource data, which happens to be designed to map directly to the facilities XML provides.
Working with arbitrary XML Resource files
You can use facilities in android to read XML files that you could use as resources. Place these xml files in
"res/xml"
Here is an example file "res/xml/test.xml"
<rootelem1>
<subelem1>
Hello World from an xml sub element
</subelem1>
</rootelem1>
aapt will compile them into efficient xml resources. Then you can use XmlPullParser to parse these files. You can get the XmlPullParser implementation using the following code from any context including activity:
Resources res = this.getResources();
XmlResourceParser xpp = res.getXml(R.xml.test);
private String getEventsFromAnXMLFile()
throws XmlPullParserException, IOException
{
StringBuffer sb = new StringBuffer();
Resources res = this.getResources();
XmlResourceParser xpp = res.getXml(R.xml.test);
xpp.next();
int eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT)
{
if(eventType == XmlPullParser.START_DOCUMENT)
{
sb.append("******Start document");
}
else if(eventType == XmlPullParser.START_TAG)
{
sb.append("\nStart tag "+xpp.getName());
}
else if(eventType == XmlPullParser.END_TAG)
{
sb.append("\nEnd tag "+xpp.getName());
}
else if(eventType == XmlPullParser.TEXT)
{
sb.append("\nText "+xpp.getText());
}
eventType = xpp.next();
}//eof-while
sb.append("\n******End document");
return sb.toString();
}//eof-function
Other important methods of XmlPullParser include
getAttributeCount
getAttributeName
getAttribute<type>Value
Note that using the android.util.AttributeSet interface, this class can use the resource references like "@id/example" in attributes and resolve them.
Working with Raw Resources
Raw resources are arbitrary file resources like audio, video, or text files that require localization or referenced through id's. These files are placed in "res/raw". Each file will have an identifier generated in R.java.
Consider the following text file
"res/raw/test.txt"
Imagine you put the following in that text file Hello world in raw resource test.txt
you can then read that file into a text string as follows
String getStringFromRawFile()
{
Resources r = getResources();
InputStream is = r.openRawResource(R.raw.test);
String myText = convertStreamToString(is);
is.close();
return myText;
}
String convertStreamToString(InputStream is)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int i = is.read();
while (i != -1)
{
baos.write(i);
i = baos.read();
}
return baos.toString();
}
However if you want to process XML files like this then you want to keep them in the "res/xml" directory and not in the "res/raw" directory. The files in this "raw" directory are not compiled and included in the package as they are.
Working with Assets
There is one more directory in Android where you can keep files to be included in the package. This directory is at the same level as "res". This means "assets" is not part of the "res" sub directories. The files in "assets" do not generate ids in R.java. One has to specify the file path to read them.
Consider the following example from one of the api demos
TypeFace mFace = Typeface.createFromAsset(
getContext().getAssets(),
"font/samplefont.ttf");
you will notice that an asset is referenced using its directory path and not a specific id. More over the file path is a relative path starting at "assets/".
One will use AssetManager class to access these files.
//Note: Exceptions are not shown in the code
String getStringFromAssetFile()
{
AssetManager am = getAssets();
InputStream is = am.open("test.txt");
String s = convertStreamToString(is);
is.close();
return s;
}
Complete directory structure
/res/values/strings.xml
/colors.xml
/dimens.xml
/attrs.xml
/styles.xml
/drawable/*.png
/*.jpg
/*.gif
/*.9.png
/anim/*.xml`
/layout/*.xml
/raw/*.*
/xml/*.xml
/assets/*.*/*.*
Notice that only the non resource directory of "assets" can contain an arbitrary list of sub directories. Every other directory can only have files at the level of that directory and no deeper. This is how R.java generates identifiers for those files.
References
1. Resources and Internationalization from SDK documentation
http://code.google.com/android/devel/resources-i18n.html
2. Available Resource Types from SDK documentation
http://code.google.com/android/reference/available-resources.html
3. System Resource Identifiers
http://code.google.com/android/reference/android/R.html
4. Resources API
http://code.google.com/android/reference/android/content/res/Resources.html
5. AssetManager API
http://code.google.com/android/reference/android/content/res/AssetManager.html