andrioidResources加载获取资源详解

getResources() 函数,大家应该都非常熟悉。
本篇文章主要讲解关于Resources相关的知识点。
主要基于以下几点讲解:

  • 定义资源
  • 解析资源
  • 加载资源

定义资源

什么是资源,图片drawable、字符串string、布局layout、主题style、颜色color、背景(selector,layer-list)等等
在android中资源:定义资源需要指定 (key - values) 键值对似的 (属性 - 值)
例如:
android:text=”hello,world”,text是属性,hello,world是值

属性的定义

  • 在我们开发中的app程序中,资源属性定义在res/values/attrs.xml 文件中
  • 而 android 系统中, 资源属性位于framework/base/core/res/res/values/attrs.xml 文件中
    定义方式大致如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <declare-styleable name="NineGridImageView">
    <attr name="singleImgSize" format="dimension" /> # 数据类型为尺寸单位 #
    <attr name="imgGap" format="dimension" />
    <attr name="maxSize" format="integer" /> # 数据类型int值 #
    <attr name="showStyle" format="enum"> # 数据类型enum枚举值 #
    <enum name="grid" value="0" />
    <enum name="fill" value="1" />
    </attr>
    </declare-styleable>
    具体讲解:
    • styleable是一个属性集合,在R.java文件中对应一组int[]数组
    • attr 是具体的属性,aapt为每个attr(属性)分配一个id值,int[]对应的id 一一映射styleable中的一个个attr
    • ,代表NineGridImageView是属性集合的名称,在一个应用程序中,这个值必须是唯一的。
    • ,singleImgSize代表每一个属性的具体名称,在一个styleable中,属性名称必须是唯一的
    • 一个attr 后面仅有一个name,则只是引用,如下(引用系统中的scaleType属性):
      1
      2
      3
      <declare-styleable name="NineGridImageView">
      <attr name="android:scaleType" />
      </declare-styleable>
    • 一般自定义声明一个attr,后面需要指定format,fromat代表的是该属性值的数据类型是什么,可回顾前面的 定义方式 参考。

值的定义

按数据类型来分类的话,有以下几种:

  • string
  • boolean
  • integer
  • float
  • enum
  • color
  • dimension
  • reference|color


注: 可以用 | 表示支持两种数据类型 如:reference|color

数据类型对应的文件夹:

  • string,boolean,int,dimension 等类型:在res/values/xxx.xml文件中
  • color类型:在res/color/xxx中
  • reference Drawable类型:在res/drawable/xxx中

解析资源

资源解析主要使用:AttributeSet和TypedArray类。

AttributeSet

AttributeSet 处于 包android.util.AttributeSet

  • 该类包含解析元素的所有属性及属性值

  • Attribute对象一般通过View的构造函数的参数传递过来,如:

    1
    publlic TextView(Context context,AttributeSet attrs,int defStyle)
  • Attribute 相关API详解,如下布局:

    1
    2
    3
    4
    5
    6
    7
    <TextView
    android:id="@+id/text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/hello_world"
    style="@stylel/text"
    />
  • 操作特定系统属性

    1
    2
    3
    4
    String getIdAttribute()  获取id属性对应的值,如果没有指定返回null
    String getStyleAttribute(),获取style属性对应的资源值,即:R文件中对应的R.style。text的值,没有为0
    int getIdAttributeResourceValue(int defaultValue),返回id属性对应的int值,此处对应为R.id.text
    ... 其他api略,太多,可以自行查阅
  • 操作通用属性

    1
    2
    3
    4
    5
    6
    int getAttributeCount(),获取属性的数目,本例中返回5
    String getAttributeName(int index),根据属性所在位置返回相应的属性名称。例如,id=0,layout_width=1,layout_height=2,text=3,style=4,如果getAttributeName(2),则返回layout_height,不包含前缀
    String getAttributeValue(int index),根据位置返回值。例中,getAttributeValue(2)则返回"wrap_content"。
    String getAttributeValue(String namespace,String name),返回指定命名空间,指定名称的属性值,该方法说明AttributeSet允许给一个XML Element的属性增加多个命名空间的属性值。
    int getAttributeResource(int index),返回指定位置的属性id值。例中,getAttributeResource(2)返回R.attr.layout_width。前面也说过,系统会为每一个attr分配一个唯一的id。
    ... 其他api略,太多,可以自行查阅
  • 获取特定类型的值

    1
    XXXType getAttributeXXXType(int index,XXXType defaultValue),其中XXXType包括int、boolean、float等类型。该方法仅适用于特定的类型,如使用不对,会返回错误

    TypedArray

TypedArray是对AttributeSet数据类的某种抽象,类似于可以直接获取到对应资源自动生成的R文件中的值
比如: android:text=”@string/hello_world”如果使用AttributeSet的方法,仅仅能获取”@string/hello_world”字符串。而实际上该字符串对应了一个string类型的数据。

主要使用方法获取TypedArray:

1
TypedArray a = context.obtainStyledAttributes(attrs,com.android.internal.R.styleable.XXX,defStyle,0);
  • 第一个参数 attrs 参数是一个AttributeSet对象,自定义view可以在构造中后获取
  • 第二个参数 是自定义的styleable
  • 参数 三和四 可以不给
    TypedArray 提供了获取内部每个attr的值,比如:
  • TypedArray.getColor(R.styleable.attrName, defaultColor); 通过指定attr名称,获取它对应的color值
  • 其他类型获取的使用的方法:
    • getDimensionPixelSize
    • getBoolean
    • getResourceId
    • getDrawable
    • getString
  • 使用完成之后需要调用TypedArray.recycle();回收内存

加载资源

Resources对象一般用来获取R.xx.xx文件,也就是获取前面说到的属性对应的资源值所对应的文件。

Context获取Resources

  • Context提供了getResources()方法,调用如下代码即可获取:

    1
    Resources mResources = Context.getResources();
  • 另外以下类与 Context 有扯不开的关系,所以以下类中基本也可以直接(或间直接BroadcastReceiver)调用getResources()获取Resources对象:

  • android.content.Context 子类

    1
    android.content.Context --> android.content.ContextWrapper --> android.view.ContextThemeWrapper
  • AppCompatActivity的父类关系

    1
    2
    3
    4
    android.view.ContextThemeWrapper --> android.app.Activity --> 
    android.support.v4.app.SupportActivity --> android.support.v4.app.BaseFragmentActivityGingerbread-->
    android.support.v4.app.BaseFragmentActivityHoneycomb--> android.support.v4.app.BaseFragmentActivityHoneycomb -->
    android.support.v4.app.BaseFragmentActivityJB --> android.support.v4.app.FragmentActivity --> android.support.v7.app.AppCompatActivity
  • IntentService的父类关系

    1
    android.content.ContextWrapper --> android.app.Service --> android.app.IntentService
  • BroadcastReceiver与Context之间的联系

    1
    2
    3
    android.content.BroadcastReceiver{
    public abstract void onReceive(Context context, Intent intent);
    }

使用Resources加载资源

以下是Resources类的一些常用操作方法

使用自动生成的R文件获取资源

使用方式示例如下:

1
Drawable drawable = getResources().getDrawable(R.drawable.xxx);

使用方式大致类似于:

1
Xxx values = getResources().getXxx(R.Xxx.xxx);

这里就不一一列举了。

通过字符串标识加载资源

1
2
3
4
5
6
7
8
9
10
//方式1
int i= getResources().getIdentifier("icon", "drawable", getPackageName()) ; //参数1 资源名称,参数2,res对应的目录,参数惨,当前应用程序包名

//方式2
int resID = getResources().getIdentifier("org.loveandroid.androidtest:drawable/icon",null,null); //包名:资源目录/资源文件名

//方式3
int resID = getResources().getIdentifier("icon", "drawable", "org.anddev.android.testproject"); //最后一个参数包名

//返回值:如果找到了,返回资源Id,如果找不到,返回0

通过XmlResourceParser获取解析R.xml下文件

使用方式如下:

1
2
XmlResourceParser xrp = getResources().getXml(R.xml.personal);
//XmlResourceParser 获取属性对应值类似TypedArray

通过openRawResource方法读取R.raw文件

使用方式如下:

1
2
3
4
InputStream is = getResources().openRawResource(R.drawable.icon);    
Bitmap mBitmap = BitmapFactory.decodeStream(is);
Paint mPaint = new Paint();
canvas.drawBitmap(mBitmap, 40, 40, mPaint);