一、定义资源
Android 使用 XML 文件描述各种资源,包括字符串、颜色、尺寸、主题、布局、甚至是图片(selector,layer-list)。资源可分为两部分,一部分是属性,另一部分是值。对于 android:text="hello world",text 就是属性,hello,world 就是值
1. 属性的定义
在 APK 程序中,属性定义在 res/values/attrs.xml 中,在系统中属性位于
framework/base/core/res/res/values/attrs.xml 文件中。具体定义如下所示:
<declare-styleable name="Window">
<attr name="windowBackground" format="reference"/>
<attr name="windowContentOverlaly" />
<attr name="windowFrame" />
<attr name="windowTitle" />
</declare-styleable>
styleable 相当于一个属性集合,其在 R.java 文件中对应一个 int[]数组,aapt 为styleable 中的每个 attr(属性)分配一个 id 值,int[]中的每个 id 对应着 styleable中的每一个 attr。
对于,Window 相当于属性集合的名称。
对于,windowBackground 相当于属性的名称;属性名称在应用程序范围内必须唯一,既无论定义几个资源文件,无论定义几个styleable,windowBackground 必须唯一。
在 Java 代码中,变量在一个作用域内只能声明一次,但可以多次使用。attr 也是一样,只能声明一次,但可以多处引用。如上代码所示,在 Window 中声明了一个名为 windowBackground 的 attr,在 Window 中引用了一个名为windowTitle 的 attr。
如果一个 attr后面仅仅有一个 name,那么这就是引用;如果不光有 name 还有 format那就是声明。windowBackground 是属性的声明,其不能在其他 styleable 中再次声明;windowTitle 则是属性的引用,其声明是在别的 styleable 中。
2. 值的定义
常见的值一般有以下几种:
- String,Color,boolean,int 类型:在 res/values/xxx.xml 文件中指定
- Drawable 类型:在 res/drawable/xxx 中指定
- layout(布局):在 res/layout/xxx.xml 中指定
- style(样式):在 res/values/xxx.xml 中指
值的类型大致分为两类,一类是基本类型,一类是引用类型;对于 int,boolean等类型在声明属性时使用如下方式:
<attr name="width" format="integer"/>
<attr name="text" format="string" />
<attr name="centerInParent"="boolean"/>
对于 Drawable,layout 等类型在声明属性时:
<attr name="background" format="reference"/>
二、解析资源
资源解析主要涉及到两个类,一个是 AttributeSet,另一个是 TypedArray。
1. AttributeSet
该类位于 android.util.AttributeSet,纯粹是一个辅助类,当从 XML 文件解析时会返回 AttributeSet 对象,该对象包含了解析元素的所有属性及属性值。并且在解析的属性名称与 attrs.xml 中定义的属性名称之间建立联系。
AttributeSet 还提供了一组 API 接口从而可以方便的根据 attrs.xml 中已有的名称获取相应的值。
如果使用一般的 XML 解析工具,则可以通过类似 getElementById()等方法获取属性的名称和属性值,然而这样并没有在获取的属性名称与 attrs.xml 定义的属性名称之间建立联系。
Attribute 对象一般作为 View 的构造函数的参数传递过来,例如:
publlic TextView(Context context,AttributeSet attrs,int defStyle)
AttributeSet 中的 API 可按功能分为以下几类,假定 TextView 定义如下所示:
<TextView
android:id="@+id/tv"
android:layout_width="@dimen/width"
android:layout_height="wrap_content"
style="@stylel/text"/>
第一类,操作特定属性:
public String getIdAttribute()
获 取 id 属 性 对应 的 字 符 串 ,此 处 返回”@+id/tv”
public String getStyleAttribute()
获 取 style 属性 对应 的字 符串, 返回”@style/text”
public int getIdAttributeResourceValue(int defaultValue)
返回 id 属性对应的 int 值,此处对应 R.id.tv
第二类,操作通用属性
public int getAttributeCount()
获取属性的数目,本例中返回 4
public String getAttributeName(int index)
根据属性所在位置返回相应的属性名称。例如,id=0,layout_width=1,layout_height=2,style=3,如果
getAttributeName(2)
则返回 android:layout_height
public String getAttributeValue(int index)
根据位置返回值。本例中,
getAttributeValue(2)
则返回”wrap_content”。
public String getAttributeValue(String namespace,String name)
返回指定命名空间,指定名称的属性值,该方法说明 AttributeSet 允许给一个 XMLElement 的属性增加多个命名空间的属性值。
public int getAttributeResource(int index)
返回指定位置的属性 id 值。本例中,getAttributeResource(2)返回 R.attr.layout_width。前面也说过,系统会为每一个 attr 分配一个唯一的 id。
第三类,获取特定类型的值:
public XXXType getAttributeXXXType(int index,XXXType defaultValue)
其 中XXXType 包括 int、unsigned int、boolean、float 类型。使用该方法时,必须明确知道某个位置(index)对应的数据类型,否则会返回错误。而且该方法仅适用于特定的类型,如果某个属性值为一个 style 类型,或者为一个 layout类型,那么返回值都将无效。
2. TypedArray
程序员在开发应用程序时,在 XML 文件中引用某个变量通常是android:background=”@drawable/background”,该引用对应的元素一般为某个View/ViewGroup,而 View/ViewGroup 的构造函数中会通过obatinStyledAttributes 方法返回一个 TypedArray 对象,然后再调用对象中的getDrawable()方法获取背景图片。
TypedArray 是对 AttributeSet 数据类的某种抽象。对于andorid:layout_width="@dimen/width",如果使用 AttributeSet 的方法,仅仅能获取”@dimen/width”字符串。而实际上该字符串对应了一个 dimen 类型的数据。
TypedArray 可以将某个 AttributeSet 作为参数构造 TypedArray 对象,并提供更方便的方法直接获取该 dimen 的值
TypedArray a = context.obtainStyledAttributes(attrs,com.android.internal.
R.styleable.XXX,defStyle,0)
方法 obtainStyledAttributes()的第一个参数是一个 AttributeSet 对象,它包含了一个 XML 元素中定义的所有属性。第二个参数是前面定义的 styleable,appt 会把一个 styleable 编译成一个 int[]数组,该数组的内部实现正是通过遍历AttributeSet 中的每一个属性,找到用户感兴趣的属性,然后把值和属性经过重定位,返回一个 TypedArray 对象。想要获取某个属性的值则调用相关的方法即可,比如 TypedArray.getDrawbale(),TypedArray.getString()等。getDrawable(),getString()方法内部均通过 Resources 获取属性值。