Android通过 R.id.XXX 找到合适的资源是神奇的。
AFAIK,资源被编译成二进制格式,那么这个映射逻辑如何在引擎盖下工作?
也许就像这样:
例如,在 layout1.xml 中,我们得到了:
<Button android:id="@+id/button1" >
和AAPT将在R.java中生成:
public static final int button1=0x7f05000b;
当 *。apk 被生成时, @ + id / button1 将被替换为“0x7f05000b”。
因此,当我们打电话时:
findViewById(R.id.button1);
我们基本上仍然根据ID进行搜索,尽管ID是一个像0x7f05000b这样的数字。
谢谢!
我真正想知道的是,如何将资源ID整数解析为资源内容?换句话说,Android运行时如何使用资源ID作为唯一线索来查找资源内容?
例如,如何找到具有资源ID的可绘制图片?或者如何找到具有资源ID的字符串值?
答案 0 :(得分:174)
在构建时,aapt工具收集您定义的所有资源(虽然文件中有单独的文件或显式定义),并为它们分配资源ID。
资源ID是32位数字格式:PPTTNNNN。 PP是资源的包; TT是资源的类型; NNNN是该类型资源的名称。对于应用程序资源,PP始终为0x7f。
TT和NNNN值由aapt任意分配 - 基本上每个新类型分配和使用下一个可用数字(从1开始);同样,对于类型中的每个新名称,将分配和使用下一个可用编号(从1开始)。
因此,如果我们按照以下顺序处理这些资源文件:
layout/main.xml
drawable/icon.xml
layout/listitem.xml
我们看到的第一种类型是“布局”,因此给出TT == 1.该类型下的第一个名称是“main”,因此给出NNNN == 1.最终资源ID为0x7f010001。
接下来我们看到“drawable”,因此给出TT == 2.该类型的第一个名称是“icon”,因此获得NNNN == 1.最终资源ID为0x7f020001。
最后我们看到另一个“布局”,其中TT == 1和以前一样。这有一个新名称“listitem”,因此获取下一个值NNNN == 2.最终资源ID为0x7f010002。
请注意,默认情况下,aapt不会尝试在构建之间保持这些标识符相同。每次资源发生变化时,都可以获得新的标识符。每次构建它们时,都会使用当前标识符创建一个新的R.java,以便您的代码获得正确的值。因此,您必须永远不要将资源标识符保存在可以在应用程序的不同版本中使用的任何位置。
一旦资源被编译并分配了标识符,aapt将为您的源代码生成R.java文件,并生成一个名为“resources.arsc”的二进制文件,其中包含所有资源名称,标识符和值(对于来自的资源)从单独的文件中,它们的值是.apk中该文件的路径,格式可以在运行时轻松地在设备上进行映射和解析。
您可以使用命令“aapt dump resources&lt; path-to-apk&gt;”获取apk中resources.arsc文件的摘要。
二进制资源表的格式记录在资源数据结构的头文件中:
在设备上读取资源表的完整实现如下:
https://github.com/android/platform_frameworks_base/blob/master/libs/androidfw/ResourceTypes.cpp
答案 1 :(得分:7)
如果您对内部实现(设备端)感兴趣,请查看Resources.java中的loadDrawable()。有关extracting data from the resource table
的信息,请参阅hackbod的优秀答案要知道布局是如何从资源ID转换为View的,请查看LayoutInfater。java
答案 2 :(得分:5)
根据我的理解,aapt会为您的每个资源自动生成唯一ID,并将它们存储在查找表中。此查找表保存为位于“bin / resources.ap_”中的“resources.arsc”文件(这只是一个ZIP文件,因此可以使用您最喜欢的ZIP查看器打开)。查找表也作为R.java保留,如您所知,允许您使用Java引用您的资源。
如果您想了解有关ARSC文件的更多信息,我建议使用Google搜索,或查看http://code.google.com/p/android-apktool/的代码。
-Dan
答案 3 :(得分:1)
最后一点:最长时间,我没有使用相对布局,因为很多项需要在xml文件中进一步引用项目,我不知道如何引用 @id / foo 尚未定义。
<!-- doesn't work -->
<TextView android:layout_above="@id/foo">above</textview>
<TextView android:id="@+id/foo">below</textview>
然后有一天我意识到(你)可以定义引用中的id;它不必在带有id的元素中:
<!-- works -->
<TextView android:layout_above="@+id/foo">above</textview>
<TextView android:id="@id/foo">below</textview>
答案 4 :(得分:0)
神奇的是Eclipse插件和它在应用程序“gen”文件夹中自动生成的R.java文件。如果您查看此文件,您将看到R.xx.XXX中每个XXX的静态映射,其中xx可以是动画,数组,颜色和其他所有资源类型。