Android6.0之App中的资源查找过程

给定一个相同的资源ID,在不同的设备配置之下,查找到的可能是不同的资源。这个资源查找过程对应用程序来说,是完全透明的。现在就详细分析资源管理框架是如何根据ID来查找资源的。

资源按照是否有文件可以分为两类:。第一类资源是不对应有文件的,例如字符串资源,而第二类资源是对应有文件的,例如drawable资源。

分别对这两种情况进行分析。

资源ID格式

前面的文章中已经介绍了资源ID格式,这里在啰嗦一遍。

资源ID是一个32位四字节数字,格式:PPTTEEEE。

其中PP代表package id.系统资源的package id为0x1,而app自己的资源包package id为0x7f。0x1与0x7f之间的package id都合法。

TT代表资源的类型(type);

NNNN代表这个类型下面的资源项的名称(entry);

TT 和NNNN 的取值是由aapt工具随意指定的——基本上每一种新的资源类型的数字都是从上一个数字累加的(从1开始);而每一个新的资源entry条目也是从数字1开始向上累加的。

假设3个资源文件按照下面的顺序排列:

layout/main.xml

drawable/icon.xml

layout/listitem.xml

aapt会依次处理:

按照顺序,第一个资源的类型是”layout” 所以指定TT=1, 这个类型下面的第一个资源是”main” ,所以指定NNNN=1 ,最后这个资源就是0x7f010001。

第二个资源类型是”drawable”,所以指定TT=2,这个类型下的”icon” 指定NNNN =1,所以最终的资源ID 是 0x7f020001。

第三个资源类型是”layout”,而这个资源类型在前面已经有定义了,所以TT仍然是1,但是”listitem”这个名字是新出现的,所以指定NNNN=2,因此最终的资源ID 就是 0x7f010002。

也就是说NNNN是可以重复的,因为可以结合TT来区分。

从资源ID获取字符串资源

下面的代码用来获得一个app的名字。以此为入口点来分析字符串资源的查找过程。

  String appName = getResources().getString(R.string.app_name);

R.string.app_name是一个资源ID。

整个过程如下所示:

resources-8.jpg

其中第6步返回的Restable对象,通过上一篇的介绍已经知道了,它里面包含了本app所有的resoureces.arsc。

重点关注ResTable的getReouces方法:


ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag, uint16_t density,
        uint32_t* outSpecFlags, ResTable_config* outConfig) const
{
    if (mError != NO_ERROR) {
        return mError;
    }

    // 得到package  id:PP
    const ssize_t p = getResourcePackageIndex(resID);
    // 得到 type : TT
    const int t = Res_GETTYPE(resID);
    // 得到 entry: EEEE
    const int e = Res_GETENTRY(resID);

    if (p < 0) {
      ......................
        return BAD_INDEX;
    }
    if (t < 0) {
      ................
        return BAD_INDEX;
    }

    // 得到packageGroup,里面有package
    // 标准Android中app的资源包中只会包含一个package ,id为0x7f
    // 而系统资源的package  id 为 0x1
    // 也就是说PackageGroup虽然可以包含多个package,但实际上只会包含一个package
    const PackageGroup* const grp = mPackageGroups[p];
    if (grp == NULL) {
        ALOGW("Bad identifier when getting value for resource number 0x%08x", resID);
        return BAD_INDEX;
    }

    // Allow overriding density
    // 配置相关
    ResTable_config desiredConfig = mParams;
    if (density > 0) {
        desiredConfig.density = density;
    }


    Entry entry;
    // 实际上就是根据grp,t,e在resources.arsc索引资源
    status_t err = getEntry(grp, t, e, &desiredConfig, &entry);
    if (err != NO_ERROR) {
    ................
        return err;
    }
    // 根据flags判断是否是flags资源,这是处理非bag资源的
    if ((dtohs(entry.entry->flags) & ResTable_entry::FLAG_COMPLEX) != 0) {
        if (!mayBeBag) {
            ALOGW("Requesting resource 0x%08x failed because it is complex\n", resID);
        }
        return BAD_VALUE;
    }
    // ResTable_entry后面跟着的就是Res_value
    const Res_value* value = reinterpret_cast<const Res_value*>(
            reinterpret_cast<const uint8_t*>(entry.entry) + entry.entry->size);

    outValue->size = dtohs(value->size);
    outValue->res0 = value->res0;
    // 得到数据类型
    outValue->dataType = value->dataType;
    // 得到数据在字符串值池中索引数组的索引
    outValue->data = dtohl(value->data);
    if (grp->dynamicRefTable.lookupResourceValue(outValue) != NO_ERROR) {
        ALOGW("Failed to resolve referenced package: 0x%
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值