Android中资源管理机制详细分析

在Android中,所有的资源都在res目录下存放,包括drawable,layout,strings,anim等等,当我们向工程中加入任何一个资源时,会在R类中相应会为该 资源分配一个id,我们在应用中就是通过这个id来访问资源的,相信做过Andorid开发的朋友对于这些肯定不会陌生,所以这个也不是我今天想要说的,我今天想和大家一起学习的是Android是如何管理资源的,在Android系统中,资源大部分都是通过xml文件定义的(drawable是图片),如layout,string,anim都是xml文件,而对于layout,anim和strings等xml文件仅仅是解析xml文件,读取指定的值而已,但是对于layout文件中控件的解析就比较复杂了,例如对于一个Button,需要解析它所有的属性值,这个是如何实现的呢。


这里我们首先要考虑一个问题,就是一个控件有哪些属性是如何定义的?比如TextView具有哪些属性?为什么我设置TextView的样式只能用style而不能用android:theme?这些信息都是在哪里定义的,想要弄清楚这个问题,就必须从源码工程招答案,我使用的是android4.1工程,如果你使用的是其他版本的,那么可能用些出入。

先看三个文件

1、d:\android4.1\frameworks\base\core\res\res\values\attrs.xml

看到attrs.xml文件,不知道你有没有想起什么?当我们在自定义控件的时候,是不是会创建一个attrs.xml文件?使用attrs.xml文件的目的其实就是给我们自定义的控件添加属性,打开这个目录后,你会看到定义了一个叫"Theme"的styleable,如下(我只截取部分)

[html]  view plain copy print ?
  1. <declare-styleable name="Theme">  
  2.           
  3.           
  4.           
  5.         <eat-comment />  
  6.   
  7.           
  8.         <attr name="colorForeground" format="color" />  
  9.           
  10.         <attr name="colorForegroundInverse" format="color" />  
  11.           
  12.         <attr name="colorBackground" format="color" />  


在这个文件中,定义了Android中大部分可以使用的属性,这里我说的是“定义”而不是“声明”,同名在语法上面最大的区别就是定义要有format属性,而声明没有format属性。

2、d:\android4.1\frameworks\base\core\res\res\values\attrs_manifest.xml

这个文件的名字和上面的文件的名字很像,就是多了一个manifest,故名思议就是定义了AndroidManifest.xml文件中的属性,这里面有一个很重要的一句话

[html]  view plain copy print ?
  1. <attr name="theme" format="reference" />  

定义了一个theme属性,这个就是我们平时在Activity上面使用的theme属性

3、d:\android4.1\frameworks\base\core\res\res\values\themes.xml

这个文件开始定义了一个叫做"Theme" 的sytle,如下(截图部分)

[html]  view plain copy print ?
  1. <style name="Theme">  
  2.   
  3.         <item name="colorForeground">@android:color/bright_foreground_darkitem>  
  4.         <item name="colorForegroundInverse">@android:color/bright_foreground_dark_inverseitem>  
  5.         <item name="colorBackground">@android:color/background_darkitem>  
  6.         <item name="colorBackgroundCacheHint">?android:attr/colorBackgrounditem>  

这个就是我们平时在Application或者Activity中使用的Theme,从这里可以看出,Theme也是一种style,那为什么style只能永远View/ViewGorup,而Theme只能用于Activity或者Application呢?先记住此问题,我们后续会为你解答


我们再来整合这三个文件的内容吧,首先在attrs.xml文件中,定义了Android中大部分的属性,也就是说以后所有View/Activity中大部分的属性就是在这里定义的,然后在attrs_manifest.xml中定义了一个叫做theme的属性,它的值就是再themes文件中定义的Theme或者继承自“Theme”的style。


有了上面的知识后,我们再来分析上面说过的两个问题:

1、TextView控件(其他控件也一样)的属性在哪里定义的。

2、既然Theme也是style,那为什么View只能用style,Activity只能使用theme?


所有View的属性定义都是在attrs.xml文件中的,所以我们到attrs.xml文件中寻找TextView的styleable吧

[html]  view plain copy print ?
  1. <declare-styleable name="TextView">  
  2.          
  3.            <enum name="spannable" value="1" />  
  4.              
  5.            <enum name="editable" value="2" />  
  6.        attr>  
  7.          
  8.        <attr name="text" format="string" localization="suggested" />  
  9.          
  10.        <attr name="hint" format="string" />  
  11.          
  12.        <attr name="textColor" />  


上面的属性我只截取了部分,请注意,这里所有的属性都是进行“声明”,你去搜索这个styleable,会发现在TextView的styleable中不会找到theme这个属性的声明,所以你给任何一个view设置theme属性是没有效果的。请看下面一段代码就知道为什么了。

定义一个attrs.xml

[html]  view plain copy print ?
  1. xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.     <declare-styleable name="MyTextView">  
  4.         <attr name="orientation">  
  5.             <enum name="horizontal" value="0" />  
  6.             <enum name="vertical" value="1" />  
  7.         attr>  
  8.     declare-styleable>  
  9. resources>  
定义一个MyTextView

[java]  view plain copy print ?
  1. public class MyTextView extends TextView {  
  2.   private static final String TAG = "MyTextView";  
  3.   public MyTextView(Context context)   
  4.   {  
  5.     super(context);  
  6.   }  
  7.   public MyTextView(Context context, AttributeSet attrs)   
  8.   {  
  9.     super(context, attrs);  
  10.     //利用TypeArray读取自定义的属性  
  11.     TypedArray ta=context.obtainStyledAttributes(attrs, R.styleable.MyTextView);  
  12.     String value=ta.getString(R.styleable.MyTextView_orientation);  
  13.     Log.d("yzy""value1--->"+value);  
  14.     ta.recycle();  
  15.   }  
  16. }  


在attrs.xml我为MyTextView定义了一个orientation属性,然后再MyTextView的构造函数中去读取这个属性,这里就涉及到TypeArray这个类,我们发现得到TypeArray需要传入R.style.MyTextView这个值,这个就是系统为我们访问MyTextView这个styleable提供的一个id,当我们需要拿到orientation这个属性的值时,我们通过R.style.MyTextView_orientation拿到,由于MyTextView中没有定义或者声明theme属性,所以我们找不到R.styleable.MyTextView_theme这个id,所以导致我们无法解析它的theme属性。同样回到TextView这个styleable来,由于TextView的styleable中没有定义theme属性,所以theme对于TextView是没有用的。所以即使你在TextView里面加入theme属性,即使编译器不会给你报错,这个theme也是被忽略了的。


我们再来看看Activity的属性是如何定义的,由于Activity是在AndroidManigest.xml文件中定义的,所以我们到attrs_manifest.xml中查找。

[html]  view plain copy print ?
  1. <declare-styleable name="AndroidManifestActivity" parent="AndroidManifestApplication">  
  2.     

你可能感兴趣的:(android)