Android使用TypedArray获取资源getResourceId方法下标越界异常问题

  • Android中重复资源获取方式TypedArray
  • res文件夹的array.xml中创建资源数组
  • 需要注意TypedArray容易出现的问题


Android中重复资源获取方式TypedArray

在Android中会经常遇到使用重复的资源,比如显示用户等级;往往用户等级的icon基本都是一个尺寸只是显示的内容不一样而已。而显示的时候需要通过获取接口数据中用户等级来决定如果显示。如果按住以往的逻辑我们可能会通过if—else或者swich—case等方式来显示。(太麻烦)Android在很早的时候为我们提供了TypedArray的方式获取类似的资源。

res文件夹的array.xml中创建资源数组

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="small_grade_level_img_array">
        <item>@drawable/small_level_1</item>
        <item>@drawable/small_level_2</item>
        <item>@drawable/small_level_3</item>
        <item>@drawable/small_level_4</item>
        <item>@drawable/small_level_5</item>
        <item>@drawable/small_level_6</item>
        <item>@drawable/small_level_7</item>
        <item>@drawable/small_level_8</item>
        <item>@drawable/small_level_9</item>
        <item>@drawable/small_level_10</item>
        <item>@drawable/small_level_11</item>
        <item>@drawable/small_level_12</item>
        <item>@drawable/small_level_13</item>
        <item>@drawable/small_level_14</item>
        <item>@drawable/small_level_15</item>
    </string-array>
</resources>

可是使用“”string-array”标签创建一个字符串Array资源,里面的每一个“item”都代表一个元素而元素的默认角标从0开始到length-1。
如果想要使用刚刚创建的资源就需要声明TypedArray对象了。

Context.getResources().obtainTypedArray(R.array.small_grade_level_img_array)

通过obtainTypedArray方法就可以获得一个TypedArray对象。如果想要使用TypedArray对象中的某一个资源一般会使用getResourceId()方法。该方法如下图:

android根据资源id android资源id重复_java


从上图可以了解到getResourceId方法中有两个参数。第一个代表资源的索引。比如我们在xml中的资源有15个索引就是从0~14。不过也可以传递其他的只系统会匹配是否有对应的资源如果没有就需要使用第二个参数默认资源。也就是通过索引找不到对应的资源就会返回默认资源。默认资源就是xml中item标签里面的值。

需要注意TypedArray容易出现的问题

往往我们使用TypedArray中都会在Activity或者Adapter中初始化它。也就是Activity或者Adapter持有一个TypedArray对象。但是在一些复杂的情况中可能我们经常要刷新某一个控件或者item布局。而在刷新完之后我们并没有释放TypedArray就调用getResourceId方法。如果可以将索引控制在资源索引的范围内是没有问题的,但是一旦超出了资源的索引范围就会出现数组下标越界的错误。

android根据资源id android资源id重复_java_02


如果避免该问题,TypedArray中提供了一个recycle()方法该方法可以将资源释放。我们再试使用这个资源的时候会重新生成一个TypedArray对象。就不会出现越界的问题了。源代码如下:

/**
     * Recycles the TypedArray, to be re-used by a later caller. After calling
     * this function you must not ever touch the typed array again.
     *
     * @throws RuntimeException if the TypedArray has already been recycled.
     */
    public void recycle() {
        if (mRecycled) {
            throw new RuntimeException(toString() + " recycled twice!");
        }

        mRecycled = true;

        // These may have been set by the client.
        mXml = null;
        mTheme = null;
        mAssets = null;

        mResources.mTypedArrayPool.release(this);
    }

官方文档如下:TypedArray的getResoucedId方法