Android XML命名空间是否用于定位资源?解析其在aapt中的作用
先看你给出的布局示例:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:custom-namespace-one="http://namespace-one" xmlns:custom-namespace-two="http://namespace-two" android:layout_width="match_parent" android:layout_height="wrap_content" >
子元素使用命名空间属性的示例:
<TextView android:id="@+id/lessens_listview_textview" custom-namespace-one:foo="value1" custom-namespace-two:foo="value2"/>
接下来解答你的疑问:
1. 命名空间如何定位库中的同名属性?
命名空间的核心是区分同名属性,而在编译阶段,它的作用是映射到属性所属的包名。
当引用第三方库的自定义属性时,库的attrs.xml里定义的属性本质上绑定在库的包名下。你在布局里声明的命名空间(比如http://schemas.android.com/apk/res/com.example.libA),就是告诉aapt:这个前缀下的属性属于com.example.libA这个包的资源。你示例里的http://namespace-one只是自定义占位符,实际开发中我们会用和包名绑定的标准命名空间格式,这样aapt才能准确找到对应库的属性。
2. aapt如何识别对应的资源?
属性定义里确实不会出现命名空间,因为属性本身是属于某个包的资源,命名空间只是使用时的“索引标识”。
aapt在编译时会扫描所有依赖库和当前模块的attrs.xml,把每个属性和它所属的包名绑定,生成唯一的资源ID。当布局里出现带命名空间前缀的属性时,aapt会根据命名空间对应的包名,找到该包下定义的同名属性,将属性值编译到最终资源文件中。
举个实际例子:库A的attrs.xml定义了<attr name="foo" format="string"/>,aapt会给它分配一个资源ID(比如0x7f010001)并关联库A的包名。当你在布局里写libA:foo="value1",aapt就会把这个属性关联到库A的foo属性ID上,不会和库B的同名属性混淆。
3. http://schemas.android.com/apk/res-auto与当前包属性的关系
这个命名空间是编译时的自动映射快捷方式,它会自动关联到当前模块(包括主APP模块和所有依赖库)中定义的自定义属性。
比如你在主APP的attrs.xml里定义了自定义属性,或者依赖的第三方库有自定义属性,用res-auto作为命名空间前缀,aapt会在编译时自动匹配属性所属的包,不需要你手动写具体的包名。这在使用自定义View库时特别方便——不用记住库的包名,直接用res-auto就能引用它的自定义属性。
另外,如果你在主模块里定义了自己的自定义属性,用res-auto和用http://schemas.android.com/apk/res/[你的APP包名]效果完全一致。
内容的提问来源于stack exchange,提问作者Nate

