Android资源管理中的Theme和Style-------之总述(一)

        我们知道Android的每个View都会有许多不同的属性,同样的一个View,我们给它的属性赋予不同的值,这个View就会有不同的效果。甚至可以说,Android的界面编程,很大程度上就是给不同的View属性赋值的过程。我们通过改变View的属性值,来改变一个View的形态。比如我们通过改变layout_width和layout_height属性的值来改变一个View的大小,通过过改变Text属性的值来改变一TextView的内容,通过改变gravity属性的值来改变一个View内部的布局方式等等。
        不过,正如现实世界是复杂的一样,在实际应用当中,一个简简单单的TextView就有不下60个属性,这还不包括从它的父类(View.java)继承过来的。但是我们比较关心、经常改动的属性也就那么几个,如果每次使用一个View都要我一一为这些属性赋值,我想我会疯掉的。那该怎么办呢?
        我们就给每一个View的所有属性都指定一个默认值吧,这些默认值放到哪儿呢?放到一个叫做theme的集合里!这个集合当中的每一个元素都是一个key-value对儿。key表示View的属性,value表示属性的值,或者说是android中的某一种资源。比如我们给一个TextView的textColor属性指定的值为android:color/white,这里android:color/white就是一种资源。不过,随着应用越来越复杂,有时候光有一套甚至几套默认值,或者说是theme还不够,比如我们想改变某个TextView的所有属性当中的某40个属性的值,其它的还用默认值,你不能每次都叫我一个一个属性去改变吧。于是,我就把这40个属性和它们所对应的值放在一个集合里,这个集合就叫style。
        其实,个人的理解,Theme和style并无本质上的区别,从资源管理的角度来看,它们都表示一种从View的某个属性到Android的某项具体资源的映射关系。它们的区别在于,style是theme的一个子集,它不一定是全部的映射关系,可以是某一部分。theme是大而全的,style是短小灵活的,它们相互配合,使得我们可以方便,但又不会有遗漏地管理Android中View的属性到资源的映射关系。
        我们知道Android里面有一种叫做attr的资源,这种资源向上对应于View的各种属性,向下对应于它们的具体值,也就是Android当中的某一项具体资源,比如一个颜色值或者一个字符串等。但严格来说,我觉得attr又说不上是一种Android资源,因为资源是被使用的,是使用的客体,但attr是使用者,是使用的主体。而且它的存在是和theme与style紧密结合的,在Android资源管理模块中,Theme和AssetManager之间泾渭分明,而这个分界线就是attr。具体就是,一个attr可以引用另外一个attr,也就是在给一个attr赋值的时候,可以给它赋另外一个attr。但是这种引用关系的层级不管有多深(android中attr的引用最多支持20级),一个attr经过theme解析后,Res_value的Type绝对不会是TYPE_ATTRIBUTE,我们看下面的这个属性解析的流程图:
Android资源管理中的Theme和Style-------之总述(一)_第1张图片
        图中蓝色的theme表示ResTable::Theme类,左边五边形中的ATTR表示Res_value的类型是attr(Res_value::TYPE_ATTRIBUTE);右边五边形中的RT表示ResTable类,REF表示Res_value的类型是资源的一个引用(Res_value::TYPE_REFERENCE)。当我们去获取theme或者style中某个属性的值的时候,我们会先从theme里查找,找到后如果我们发现它的值的类型是Res_value::TYPE_ATTRIBUTE,也就是说它的值是另外一个属性,而非最终结果,那么我们就会根据这个属性再次查找,如此循环往复,直到我们得到的值的类型不再是Res_value::TYPE_ATTRIBUTE为止。但这时候,我们得到的还有可能不是最终结果,因为这个值有可能是某项资源的引用(Res_value::TYPE_REFERENCE),而不是具体的值,那么我们还需要在ResTable中循环往复地查找,直到它的值不再是Res_value::TYPE_REFERENCE类型的,而是最终值为止。在这个过程中,我们可以清晰地看到,ResTable::Theme类负责Res_value::TYPE_ATTRIBUTE类型的值的解析,它解析完后再抛给ResTable,此时它的值要么是最终值,要么是Res_value::TYPE_REFERENCE。如果是后者,那么ResTable将负责把它的最终值解析出来。
        只是这么说可能比较抽象,举个例子:
        在styles.xml文件中

<style name="myStyle"> "myTextColor1">@?attr/myTextColor2 "myTextColor2">@?attr/myTextColor3 "myTextColor3">@?attr/myTextColor4 "myTextColor4">@color/green1 style>

        而在colors.xml中

<resources>
    <color name="green1">@color/green2<\/color>
    <color name="green2">@color/green3<\/color>
    <color name="green3">#55008800<\/color>
resources>

        假设我们要去获取myTextColor1属性的值,那么ResTable::Theme类会第一次解析myTextColor1属性;然后发现它的值是另外一个attr,也就是myTextColor2,那么它会继续解析myTextColor2;然后发现myTextColor2的值也是一个attr,myTextColor3,那么它继续解析myTextColor3;然后发现myTextColor3的值还是一个attr,myTextColor4,那么它继续解析myTextColor4;解析完myTextColor4,发现它的值不再是一个attr了,ResTable::Theme的工作才算完成了,然后它会把这个值交给ResTable类去进一步解析。ResTable发现这个值也不是一个具体的颜色值,而是一个资源的引用(其实就是green1在R文件中的id),那么它会去解析这个引用green1;解析完green1后,发现它的值还是一个资源的引用green2,那么那么它会去解析这个引用green2;解析完green2,ResTable类发现它的值还是一个资源的引用green3,那么那么它会去解析这个引用green3;解析完green3,ResTable类发现它是一个具体的颜色值#55008800,于是完成资源解析的任务,最终我们得到了属性myTextColor1的最终值为#55008800。在这个过程中ResTable::Theme负责attr的解析,ResTable负责引用的解析,分工非常明确。
        我们在理解theme(或者style)和AssetManager(或者ResTable)的时候,要特别注意它们的区别:前者表示的是一种属性到具体资源(或者说是使用者到被使用者)的映射关系;后者则是纯粹表示各种资源。下一篇我们具体介绍theme和style的实现。

你可能感兴趣的:(AssetManager)