android资源和资源ID之间的映射如何工作?


76

对于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是0x7f05000b之类的数字,但我们基本上仍会根据ID进行搜索。

谢谢!

我真正想知道的是,如何将资源id整数解析为资源内容?换句话说,Android运行时如何查找以资源ID为唯一线索的资源内容?

例如,如何找到带有资源ID的可绘制图片?或如何找到带有资源ID的字符串值?

Answers:


193

在构建时,aapt工具会收集您已定义的所有资源(尽管是单独的文件或文件中的显式定义),并为其分配资源ID。

资源ID是32位数字,格式为:PPTTNNNN。PP是资源所在的包;TT是资源的类型;NNNN是该类型资源的名称。对于应用程序资源,PP始终为0x7f。

TT和NNNN值由aapt任意分配-基本上,对于每种新类型,都会分配并使用下一个可用数字(从1开始);同样,对于类型中的每个新名称,将分配并使用下一个可用编号(从1开始)。

因此,如果我们由aapt按以下顺序处理这些资源文件:

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

我们看到的第一种类型是“ layout”,因此被赋予TT ==1。该类型下的名字是“ main”,因此被赋予NNNN ==1。最终资源ID为0x7f010001。

接下来,我们看到“可绘制”,从而得到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 <path-to-apk>”在apk中获得resources.arsc文件的摘要。

二进制资源表的格式记录在资源数据结构的头文件中,此处:

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

读取设备上资源表的完整实现在这里:

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


顺便说一句,这些细节是否记录在某处?
smwikipedia'7

除了我链接到这里的结构定义之外,没有记录实现细节。
hackbod 2011年

1
顺便说一句,恕我直言,“ RTFSC”是错误的。来源是对规格的解释,可以更改。如果没有规范,则行为是正式未定义的。阅读源代码只会告诉您作者在编写规范时的想法。它告诉您现在发生什么,但不会告诉您以后会发生什么。戴安娜的出色解释仍然可能会为您提供所需的知识,并在可预见的未来保持相关性。
爱德华·福尔克

@ edward-falk:我认为RTFSC在这里是正确的,因为首先的问题是关于引擎盖下的东西(从来没有正式指定),而不是API。内部规格是SC :)
端口443

在构建或运行时是否解析对XML中的字符串和其他值的引用?<TextView text =“ @ string / foo” />?
jophde


5

据我了解,aapt将为您的每个资源自动生成唯一的ID,并将其存储在查找表中。此查找表将作为“ bin / resources.ap_”中的“ resources.arsc”文件保留(这只是一个ZIP文件,因此可以使用您喜欢的ZIP查看器打开)。该查找表也保存为R.java,您知道该查找表允许您使用Java引用资源。

如果您想了解有关ARSC文件的更多信息,建议您使用Google搜索,或查看http://code.google.com/p/android-apktool/的代码。

-担


感谢您提供重要线索。我将进行搜索。如果没有更好的答案,我会标记您的答案。谢谢。
smwikipedia'7

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>

0

神奇之处在于Eclipse插件及其在应用程序的“ gen”文件夹中自动生成的R.java文件。如果您查看此文件,将在R.xx.XXX中看到每个XXX的静态映射,其中xx可以是动画,数组,颜色和其他所有资源类型。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.