我想弄清楚“编译资源”是什么意思。
我读过很多关于这个主题的文章,但没有找到一个简单的答案。 我读过的最好的是:How does the mapping between android resources and resources ID work?。
根据我的理解,当我们通过ANT(Eclipse)或Gradle(AS)编译项目时。 我们使用名为 aapt 的工具 - Android资产包装工具: 用于为我们的每个资源生成唯一ID,例如我们的布局,样式等,并将它们存储在查找表中。然后它通过生成两个文件来保留此查找表:
所以为了简单起见:假设我在activity_main.xml中有这个:
<TextView android:id="@+id/my_textView"
android:text="@string/hello_world"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
我在onCreate中使用:
来调用它findViewById(R.id.my_textView)
在我的R.java文件中,我将看到:
public static final int my_textView=0x7f08003f;
在生成的apk上使用:aapt dump资源我可以看到它包含my_textView的两行: ec资源0x7f08003f com.example.lizi.liortest2:id / my_textView:flags = 0x00000000 资源0x7f08003f com.example.lizi.liortest2:id / my_textView:t = 0x12 d = 0x00000000(s = 0x0008 r = 0x00)
我原以为这个resources.arsc文件不仅包含资源ID,还包含我为视图定义的所有属性,例如android:layout_width =“wrap_content”。
所以现在在运行时VM尝试运行findViewById(R.id.my_textView)
它如何知道要创建哪个视图/其属性?
我根本无法理解它是如何工作的......这个查找表是否也不包含属性数据? 什么是0x7f08003f号码? (它是否应表示稍后将映射到将存储对象的物理内存的值?)
答案 0 :(得分:24)
TL; DR :在android编译器(aapt)的帮助下,xml节点将被转换为Java类,并将相应的属性转换为数字ID。 Android运行时使用这些ID来实例化类以创建视图
运行此命令以转储二进制文件xml
aapt d xmltree apk_file_name res/layout/activity_main.xml
( aapt可在 android-sdk-dir / build-tools / 23.0.2 / aapt.exe 中找到)
这将显示xml节点(例如LinearLayout
,RelativeLayout
等)及其属性(例如android:layout_width, android:layout_height
)及其值。请注意,可以在那里看到常量match_parent
(数值0xffffffff
或-1
)或wrap_content
(数值0xfffffffe
或-2
)
事实上,您可以在apk中的任何其他xml文件上使用此命令,例如AndroidManifest.xml or layout files
apk文件只是一个zip存档,包含所有java类文件(classes.dex
),所有已编译的资源文件和一个名为resources.arsc
的文件。
此resource.arsc
文件包含有关资源的所有元信息,xml节点(例如LinearLayout
,RelativeLayout
等),其属性(例如android:layout_width
),资源id
的。这些资源id
指的是apk文件中的真实资源。属性在运行时解析为值。对于任何重定向(@dimen/...
而不是4dp
或@color/...
而不是"#FFaabbcc"
),解决过程都很明智,并返回一个可用值({{1} }值的解析方式与dimen
值不同。
什么是编译的XML文件:
已编译的XML文件与XML文件相同,资源引用已更改为其对应的color
。例如,引用ids
将替换为@string/ok
。此外,0x7f000001
命名空间中的属性更改为各自的整数值(例如android
更改为wrap_content
或0xfffffffe
)
Android如何在运行时解析资源:
方法inflater.inflate()
解析已编译的xml文件,并通过实例化xml节点来创建视图层次结构。每个xml节点都由java类实例化(例如LinearLayout.java,RelativeLayout.java)。要实例化,inflater会解析已编译的xml文件,收集节点的所有属性,并creates类型为AttributeSet
的压缩结构。这个-2
被传递给类构造函数。类构造函数负责遍历AttributeSet
并解析每个属性值。
例如,对于包含AttributeSet
的布局,RelativeLayout
会将inflater
和layout_width
打包到layout_height
并将其传递给构造函数{{ 3}}。在这种情况下,某些属性及其值由RelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)解析,其余属性由父RelativeLayout.initFromAttributes()解析。
AttributeSet
视图只是另一个属性。在实例化之后,inflater将ViewGroup.initFromAttributes()的每个视图的id存储在该视图上
现在回答您的问题
android:id
是一个java数组,R.id
是该数组中的整数。视图my_textview
的{{1}}是此整数(以0x7f开头)。方法calling setId(id)
在该视图层次结构上执行深度优先搜索,以查找相应的视图。
希望这会有所帮助。您在问题中提供的findViewById()
已经回答了如何通过aapt生成ID。
这是一个管理多种维度设备资源的精彩系统。而且,实施真的很快!!以此为基础,它允许实现更高级别的功能(例如link)
答案 1 :(得分:2)
LayoutInflater通过使用XML字符串来扩充视图。正如您在问题中提到的那样,XML字符串被编译到资源文件中。
请查看AOSP的以下代码段:
public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
if (DEBUG) {
Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
+ Integer.toHexString(resource) + ")");
}
final XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
Resources.getLayout
加载XML资源解析器
public XmlResourceParser getLayout(int id) throws NotFoundException {
return loadXmlResourceParser(id, "layout");
}
XmlResourceParser loadXmlResourceParser(int id, String type)
throws NotFoundException {
synchronized (mAccessLock) {
TypedValue value = mTmpValue;
if (value == null) {
mTmpValue = value = new TypedValue();
}
getValue(id, value, true);
if (value.type == TypedValue.TYPE_STRING) {
return loadXmlResourceParser(value.string.toString(), id,
value.assetCookie, type);
}
throw new NotFoundException(
"Resource ID #0x" + Integer.toHexString(id) + " type #0x"
+ Integer.toHexString(value.type) + " is not valid");
}
}
getValue
使用AssetManager&#39; getResourceValue,并调用loadResourceValue
本机方法。此本机方法调用ResTable
&n; getResource方法来获取存储在资源文件中的XML字符串。
答案 2 :(得分:0)
Use appt for android-sdk (ex:- /build-tools/27.0.3/aapt )
run given script and get resources.arsc file content
./aapt dump resources ./debug.apk
Package Groups (1)
Package Group 0 id=0x7f packageCount=1 name=com.dianping.example.activity
Package 0 id=0x7f name=com.dianping.example.activity
type 1 configCount=3 entryCount=1
spec resource 0x7f020000 com.example.activity:drawable/ic_launcher: flags=0x00000100
config mdpi-v4:
resource 0x7f020000 com.example.activity:drawable/ic_launcher: t=0x03 d=0x00000000 (s=0x0008 r=0x00)
config hdpi-v4:
resource 0x7f020000 com.example.activity:drawable/ic_launcher: t=0x03 d=0x00000001 (s=0x0008 r=0x00)
config xhdpi-v4:
resource 0x7f020000 com.example.activity:drawable/ic_launcher: t=0x03 d=0x00000002 (s=0x0008 r=0x00)
type 2 configCount=1 entryCount=1
spec resource 0x7f030000 com.dianping.example.activity:string/app_name: flags=0x00000000
config (default):
resource 0x7f030000 com.dianping.example.activity:string/app_name: t=0x03 d=0x00000003 (s=0x0008 r=0x00)
此链接可能会帮助http://elinux.org/Android_aapt