80

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运行时是如何定位以resource id为唯一线索的资源内容的呢?

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

4

5 回答 5

198

在构建时,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。

接下来我们看到“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 <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

于 2011-07-11T05:29:33.220 回答
8

如果您对内部实现(设备端)感兴趣,请查看Resources.java中的 loadDrawable() 。有关从资源表中提取数据的 信息,请参阅 hackbod 的优秀答案

要了解布局如何从资源 ID 转换为视图,请查看LayoutInfater .java

于 2011-06-29T08:15:18.557 回答
6

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

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

-担

于 2011-07-05T12:02:12.860 回答
1

最后一点:长期以来,我没有使用相对布局,因为许多项目需要在 xml 文件中进一步引用项目,而且我不知道如何引用尚未定义的@id/foo然而。

<!-- doesn't work -->
<TextView android:layout_above="@id/foo">above</textview>
<TextView android:id="@+id/foo">below</textview>

然后有一天我意识到(duh)你可以在引用中定义一个 id;它不必在带有 id 的元素中:

<!-- works -->
<TextView android:layout_above="@+id/foo">above</textview>
<TextView android:id="@id/foo">below</textview>
于 2013-09-14T16:29:00.220 回答
0

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

于 2011-06-29T07:46:01.333 回答