How Does the Mapping Between Android Resources and Resources Id Work

How does the mapping between android resources and resources ID work?

At build time, the aapt tool collects all of the resources you have defined (though separate files or explicit definitions in files) and assigns resource IDs to them.

A resource ID is a 32 bit number of the form: PPTTNNNN. PP is the package the resource is for; TT is the type of the resource; NNNN is the name of the resource in that type. For applications resources, PP is always 0x7f.

The TT and NNNN values are assigned by aapt arbitrarily -- basically for each new type the next available number is assigned and used (starting with 1); likewise for each new name in a type, the next available number is assigned and used (starting with 1).

So if we have these resource files handled by aapt in this order:

layout/main.xml
drawable/icon.xml
layout/listitem.xml

The first type we see is "layout" so that is given TT == 1. The first name under that type is "main" so that is given NNNN == 1. The final resource ID is 0x7f010001.

Next we see "drawable" so that is given TT == 2. The first name for that type is "icon" so that gets NNNN == 1. The final resource ID is 0x7f020001.

Last we see another "layout" which has TT == 1 as before. This has a new name "listitem" so that gets the next value NNNN == 2. The final resource ID is 0x7f010002.

Note that aapt by default makes no attempt to keep these identifiers the same between builds. Each time the resources change, they can all get new identifiers. Each time they are built, a new R.java is created with the current identifiers so your code gets the correct values. Because of this, you must never persist resource identifiers anywhere where they can be used across different builds of your app.

Once the resources are compiled and identifiers assigned, aapt generates the R.java file for your source code and a binary file called "resources.arsc" that contains all of the resource names, identifiers, and values (for resources that come from separate file, their value is the path to that file in the .apk), in a format that can easily mmapped and parsed on the device at runtime.

You can get a summary of the resources.arsc file in an apk with the command "aapt dump resources <path-to-apk>".

The format of the binary resource table is documented in the header file for the resource data structures here:

https://github.com/android/platform_frameworks_base/blob/master/libs/androidfw/include/androidfw/ResourceTypes.h

The full implementation for reading the resource table on the device is here:

https://github.com/android/platform_frameworks_base/blob/master/libs/androidfw/ResourceTypes.cpp

resource ID R.id.map is added automatically to the Android project when you build the layout file

You are not dynamically inserting the framgent, instead you are finding the map fragment using findFragmentById. This means that you need to have the map fragment in your layout file.

You are probably missing the following in your layout file

<fragment
android:id="@+id/map"
android:name="com.google.android.gms.maps.MapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />

Are integer value of view IDs are always constant in android?

For any particular app resource, the particular R class associated resource ID will be the same in all scenarios during runtime as this resource ID is generated by aapt during compile time.

From Android Documentation:

Once you provide a resource in your application, you can apply it by referencing its resource ID. All resource IDs are defined in your project's R class, which the aapt tool automatically generates. When your application is compiled, aapt generates the R class, which contains resource IDs for all the resources in your res/ directory.

Thus printing it in two devices will result the same int value, provided that the same apk is used. Also note that the resource id is final in the respective R subclass.

From this answer:

Note that aapt by default makes no attempt to keep these identifiers
the same between builds. Each time the resources change, they can all
get new identifiers. Each time they are built, a new R.java is created
with the current identifiers so your code gets the correct values.
Because of this, you must never persist resource identifiers anywhere
where they can be used across different builds of your app.

Any changes to the resource might make the resource get an new R class resource ID.

Based on the way in which the R class Resource ID are calculated, as described in that answer, I think since you only changed the name of the XML resource ID, and didn't change the type of the resource nor the placement of the respective View object declaration in the respective XML file, the same R class Resource ID is being calculated.

What is the use of the res/values/public.xml file on Android?

The file res/values/public.xml is used to assign fixed resource IDs to Android resources.

Consider these set of string resources in res/values/strings.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="string1">String 1</string>
<string name="string3">String 3</string>
</resources>

The Android Asset Packaging Tool (aapt) might assign the following resource IDs for these resources when the app is compiled:

public final class R {
// ...
public static final class string {
public static final int string1=0x7f040000;
public static final int string3=0x7f040001;
}
}

Now, change the set of string resources to

<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="string1">String 1</string>
<string name="string2">String 2</string>
<string name="string3">String 3</string>
</resources>

and you'll notice that the resource ID for @string/string3 has changed:

public final class R {
// ...
public static final class string {
public static final int string1=0x7f040000;
public static final int string2=0x7f040001;
public static final int string3=0x7f040002; // New ID! Was 0x7f040001
}
}

To prevent this, you can use res/values/public.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<public type="string" name="string3" id="0x7f040001" />
</resources>

which will result in the resource IDs being assigned as follows:

public final class R {
// ...
public static final class string {
public static final int string1=0x7f040000;
public static final int string2=0x7f040002;
public static final int string3=0x7f040001; // Resource ID from public.xml
}
}

Applications rarely have any use for res/values/public.xml since the resource IDs assigned to resources does not matter. When they change, the entire application is rebuilt anyway so any references in Java code to resources by resource ID will be updated.

The most significant user of res/values/public.xml is the Android platform itself. Applications built against old versions of Android assumes that certain resource have a certain resource ID. For example, the Android resource @android:style/Theme must always have the resource ID 0x01030005 for the platform to be backwards compatible with apps built against old versions of the platform.

If you are curious about more details on how resource IDs are assigned, please refer to this answer: How does the mapping between android resources and resources ID work?

Android compiled resources - resources.arsc

TL;DR: With the help of android asset packagin tool(aapt), xml nodes get translated to Java classes and the corresponding xml attributes get translated to numerical Ids. Android run-time works with these numeric ids to instantiate classes and create the views

TL;R

Run this command to dump the binary xml

aapt d xmltree apk_file_name res/layout/activity_main.xml(aapt can be found in android-sdk-dir/build-tools/23.0.2/aapt.exe)

This will show the xml nodes (e.g. LinearLayout, RelativeLayout, etc) with their attributes(e.g. android:layout_width, android:layout_height) and their values. Note that, the constants match_parent(numeric value 0xffffffff or -1) or wrap_content(numeric value 0xfffffffe or -2) can be seen there.

As a matter of fact, you can use this command on any other xml files in the apk e.g. AndroidManifest.xml or other layout files

The apk file is just a zip archive containing all the java class files(classes.dex), all the compiled resource files and a file named resources.arsc.
This resource.arsc file contains all the meta-information about the resources. Some of those are...

  • the xml nodes(e.g. LinearLayout, RelativeLayout, etc),
  • the attributes(e.g. android:layout_width),
  • the resource id's.

The resource id's refer to the real resources in the apk-file. The attributes are resolved to a value at runtime. The resolution process is smart about any re-direction (@dimen/... as opposed to 4dp or @color/... as opposed to "#FFaabbcc") and returns a usable value(a dimen value is resolved differently than a color value).

Whats a compiled XML file:
A compiled XML file is just the same XML file with the resource references changed to their corresponding ids. For example, a reference @string/ok will be replaced by 0x7f000001. Moreover, the attributes from android namespace is changed to their respective integer values(e.g. wrap_contentis changed to 0xfffffffe or -2)

How Android resolves resources at runtime:
The methodinflater.inflate() parses a compiled xml file and creates a view hierarchy by instantiating the xml nodes. Each of the xml nodes is instantiated by a java class(e.g. LinearLayout.java, RelativeLayout.java). To instantiate, the inflater parses the compiled xml file, collects all the attributes of a node and creates a packed structure of type AttributeSet. This AttributeSet is passed to the class constructor. The class constructor has the responsibility of walking the AttributeSet and resolving each of the attribute values.

For example, for a layout containing RelativeLayout, the inflater will pack layout_width and layout_height into a AttributeSet and pass it to the constructor

RelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes).

In this case, some of the attributes are resolved by RelativeLayout.initFromAttributes(). The rest of the attributes are resolved by the parent ViewGroup.initFromAttributes(). The attribute android:id of a view is just another attribute. After inflating, the inflater stores the id of each view by calling setId(id) on that view after instantiation

Now to answer your question
R.id is a java array and R.id.my_textview is an integer in that array. The id of the view my_textview is this integer(starts with 0x7f). The method findViewById() does a depth-first search on that view hierarchy to find the respective view.

Hope this helps. The link you provided in your question already answers how the ids are generated by aapt.

Its a wonderful system of managing resources for devices with multiple dimensions of variations. Moreover, the implementation is really fast !! With this as the foundation, it allows to implement higher level functionality(e.g. Runtime Resource Overlay)

What limits are there on the number of Android resources?

After a lot of experimenting, it seems that you can have up to 16 bits worth of resources (65,536 resources) for each resource type. (There may be additional bits reserved for future use, which would reduce the max resource count, but I couldn't find any evidence of this.) It would be nice if someone could provide an authoritative answer, but after a year, I'm giving up.

EDIT (see the comment below by @B T): Based on this answer by hackbod in another thread, It seems that there are, indeed, 16 bits available, so one can have up to 65,535 resources of any one type (not 65,536, because zero is not available). Also, note that this limit applies only to the number of resources for a single configuration (locale, pixel density, etc.). Variations of a resource for different configurations share the same resource ID and don't contribute to the count. So you can actually have a lot more than 65,535 resources of any one type (e.g., layout or string), just not for any one configuration.

Are resources final in Android?

The ids are converted to a unique integer value and by switching on the value of R.id.myvalue that int value will always map to that resource.

The linked question is from 2011.

As for if or switch, if you have only a couple of values then an if statement might be better, a longer list then a switch, which is programming basics. Please note this is not set in stone. When to use If-else if-else over switch statments and vice versa



Related Topics



Leave a reply



Submit