Resources资源的查找过程

以setContentView为列

1、Activity.setContentView

2、PhoneWindow.setContentView
. LayoutInflater.inflate(layoutResID, mContentParent)

3、 LayoutInflater.inflate
getContext().getResources().getLayout(resource)返回XmlResourceParser,然后调用其成员函数inflate(parser, root, attachToRoot);

4、Resources.getLayout(resourceId)
    loadXmlResourceParser(resourceId, "layout");

5、Resources.loadXmlResourceParser
getValue(id, value, true);得到资源文件的名称
loadXmlResourceParser(value.string.toString(), id, value.assetCookie, type);value 为TypeValue类型。

6、Resources.getValue
mAssets.getResourceValue(id, outValue, resolveRefs); mAssets为AssetManager类型

7、AssetManager.getResourceValue
loadResourceValue(ident, outValue, resolveRefs);返回Int,结果值保持在outValue中,sringBlock数组中的每一个StringBlock对象描述的都是当前应用程序使用的每一个资源索引表的资源项值字符串资源池,当AssetManager类的成员函数loadResourceValue的返回值block大于等于0的时候,实际上就表示参数ident所描述的资源项在当前应用程序使用的第block个资源索引表中。

C++层

8、AssetManager.loadResourceValue
 loadResourceValue()JNI方法,得到C++层的AssetsManager,调用其getResources方法,返回ResTable,资源表, 调用ResTable对象的成员函数getResource来获得与参数ident所对应的资源项值及其配置信息,并且保存在类型为Res_value的变量value以及类型为ResTable_config的变量config中。
 如果参数resolve的值等于true,那么就继续调用上述得到的ResTable对象的成员函数resolveReference来解析前面所得到的资源项值
调用函数copyValue将上述得到的资源项值及其配置信息拷贝到参数outValue所描述的一个Java层的TypedValue对象中去,返回调用者可以获得与参数ident所对应的资源项内容。

9、 AssetManager.getResources
   getResTable(required):返回ResTable
当前应用程序所使用的资源包有两个,其中一个是系统资源包,即/system/framework/framework-res.apk,另外一个就是自己的APK文件。这些APK文件的路径都分别使用一个asset_path对象来描述,并且保存在AssetManager类的成员变量mAssetPaths中。

9.1、检查资源包里面的resources.arsc文件已经提取出来,调用当前正在处理的AssetManager对象的成员变量mZipSet所指向的一个ZipSet对象的成员函数getZipResourceTableAsset就可以获得一个对应的Asset对象,mZipSet所指向的一个ZipSet对象。
9.2、如果资源包里面的resources.arsc文件还没有提取出来,那么就会调用当前正在处理的AssetManager对象的成员函数openNonAssetInPathLocked来将该resources.arsc文件提取出来。
9.3、Asset对象ass添加到变量rt所描述的一个ResTable对象中去,这是通过调用该ResTable对象的成员函数add来实现的

10、ResTable.getResource
参数resID描述的是要查找的资源的ID,ResTable类的成员函数getResource分别获得它的Pakcage ID、Type ID以及Entry ID,保存在变量p、t以及e中。知道了Pakcage ID之后,就可以在ResTable类的成员变量mPackageGroups中找到对应的PakcageGroup

11、ResTable.getEntry

12、ResTable.resolveReference
ResTable类的成员函数resolveReference的实现其实很简单,它就是对参数value所描述的一个资源项值进行解析,前提是这个资源项值是一个引用。一个资源项的值有可能是嵌套引用的,也就是可能是引用的引用,因此,ResTable类的成员函数resolveReference需要使用一个while循环来不断地对参数value所描述的一个资源项值进行解析,直到最后一次解析出来的结果不是引用为止。但是,为了防止无限地解析下去,该while循环最多只允许执行20次。每一次解析都是调用ResTable类的成员函数getResource来实现的,沿着调用路径最终返回到前面的Step 5中,即Resources类的成员函数loadXmlResourceParser中,我们就可以得到参数id所描述的资源项的值了。

13、Resources.loadXmlResourceParser
Resources类最多可以缓存最近读取的四个Xml资源文件的内容,读取超过四个Xml资源文件之后 ,XmlBlock数组和资源ID数组就会被循环利用。
mCachedXmlBlockIds所指向的资源ID数组中检查是否存在一个资源ID与参数id所描述的资源ID相等。如果存在的话,那么就会在成员变量mCachedXmlBlocks所指向的XmlBlock数组中找到一个对应的XmlBlock对象,并且调用这个XmlBlock对象的成员函数newParser来创建一个XmlResourceParser对象返回给调用者。
 如果在Resources类的成员变量mCachedXmlBlockIds所指向的资源ID数组找到对应的资源ID的话,那么Resources类的成员函数loadXmlResourceParser就会调用成员变量mAssets所指向的一个Java层的AssetManager对象的成员函数openXmlBlockAsset来打开参数file所指定的Xml资源文件,从而获得一个XmlBlock对象block。这个XmlBlock对象block以及参数id所描述的资源ID同时也会被缓存在Resources类的成员变量mCachedXmlBlocks和mCachedXmlBlockIds所描述的XmlBlock数组和资源ID数组中。 最后,Resources类的成员函数loadXmlResourceParser就可以调用前面得到的XmlBlock对象block的成员函数newParser来创建一个XmlResourceParser对象返回给调用者。

14、AssetManager.openXmlBlockAsset

15、AssetManager.openXmlBlockAsset
        JNI方法,调用它的成员函数openNonAsset来打开参数fileName所指定的Xml资源文件,接下来就会创建一个ResXMLTree对象,并且将前面所打开的Xml资源文件的内容设置到该ResXMLTree对象中去,并且将该ResXMLTree对象的地址值返回给调用者。

16、AssetManager.openNonAsset
 AssetManager类的成员函数openNonAsset通过参数cookie知道了当前要打开的文件是位于哪个APK文件之后,接着就继续调用另外一个成员函数openNonAssetInPathLocked来打开该文件

17、 AssetManager.openNonAssetInPathLocked
如果参数ap描述的文件路径是一个目录,那么它就会直接将参数fileName所指向的文件名称附加到该目录后面去,然后直接调用另外一个成员函数openAssetFromFileLocked来打开参数fileName所指向的文件。如果打开失败,那么就再假定参数ap描述的文件路径是一个以“.gz“为后缀的压缩包,然后再次调用成员函数openAssetFromFileLocked来打开参数fileName所指向的文件。 如果参数ap描述的文件路径是一个普通文件,那么就意味着参数ap描述的是一个压缩文件,因此,它就会先调用成员函数getZipFileLocked来打开该压缩文件,然后再调用成员函数openAssetFromZipLocked来在该压缩包将参数fileName所指向的文件提取出来。Android应用程序的资源一般都是打包在一个APK文件里面的,而APK文件就是一个Zip格式的压缩包,因此,AssetManager类的成员函数openNonAssetInPathLocked一般就是按照第二种方式来打开参数fileName所指向的文件。

18、AssetManager.openAssetFromZipLocked
就是从参数pZipFile所描述的压缩包中将参数entryName所描述的文件提取出来,并且根据提取出来的内容保存在一个Asset对象中返回给调用者。

19、 XmlBlock.newParser
 XmlBlock类的成员函数mNative指向的是C++层的一个ResXMLTree对象,调用JNI方法nativeCreateParseState,用来在C++层创建一个ResXMLParser对象,最后再将该C++层的ResXMLParser对象封装成Java层的一个Parser对象中,并且将该Parser对象返回给调用者

20、 LayoutInflater.inflate
 LayoutInflater类的成员函数inflate主要负责处理前面所打开的Xml资源文件的根节点,然后再调用另外一个成员函数rInflate来处理根节点的子节点。每一个节点都表示一个UI控件,这个UI控件是通过调用LayoutInflater类的成员函数createViewFromTag来创建的。

21、LayoutInflater.createViewFromTag
LayoutInflater类的成员函数createViewFromTag接下来检查成员变量mFactory的值是否不等于null。如果不等于null的话,那么它就会指向一个Factory对象,该Factory对象描述的是一个UI控件创建工厂,专门用来负责创建UI控件。
如果LayoutInflater类的成员变量mFactory的值等于null,那么LayoutInflater类的成员函数createViewFromTag就会调用成员函数onCreateView或者createView来创建由参数name所指定的UI控件,取决于参数name是否包含了一个“.”字符。注意,如果参数name是否包含了一个“.”字符,那么就说明当前所创建的UI控件是一个用户自定义的UI控件,也就是不是Android提供的标准控件。

22、 PhoneLayoutInflater.onCreateView
  PhoneLayoutInflater类的成员函数onCreateView只负责创建两类标准的UI控件,一种是属于android.widget包的,另一种是属于android.webkit包的,其中,优先创建android.widget包的UI控件。
 如果参数name所描述的UI控件既不属于android.widget包的,也不属于android.webkit包的,那么 PhoneLayoutInflater类的成员函数onCreateView就会将创建UI控件的操作交给父类来处理,即通过调用父类的成员函数onCreateView来创建。
如果参数name所描述的UI控件是属于android.widget包或者android.webkit包的,那么PhoneLayoutInflater类的成员函数onCreateView就会直接调用父类LayoutInflater的成员函数createView来创建参数name所描述的UI控件,因此,接下来我们就继续分析LayoutInflater类的成员函数createView的实现。

23、 LayoutInflater.createView

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,482评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,377评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,762评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,273评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,289评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,046评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,351评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,988评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,476评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,948评论 2 324
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,064评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,712评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,261评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,264评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,486评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,511评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,802评论 2 345

推荐阅读更多精彩内容