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、Layout(resourceId)
loadXmlResourceParser(resourceId, "layout");
5、Resources.loadXmlResourceParser
getValue(id, value, true);得到资源⽂件的名称
loadXmlResourceParser(String(), id, value.assetCookie, type);value 为TypeValue类型。
6、Value
7、ResourceValue
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、 Resources
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、Resource
参数resID描述的是要查的资源的ID,ResTable类的成员函数getResource分别获得它的Pakcage ID、Type ID以及Entry ID,保存在变量p、t以及e中。知道了Pakcage ID之后,就可以在ResTable类的成员变量mPackageGroups中到对应的PakcageGroup
11、Entry
12、solveReference
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、 wParser
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、ateViewFromTag
LayoutInflater类的成员函数createViewFromTag接下来检查成员变量mFactory的值是否不等于null。如果不等于null的话,那么它就会指向⼀个Factory对象,该Factory对象描述的是⼀个UI控件创建⼯⼚,专门⽤来负责创建UI控件。
如果LayoutInflater类的成员变量mFactory的值等于null,那么LayoutInflater类的成员函数createViewFromTag就会调⽤成员函数
onCreateView或者createView来创建由参数name所指定的UI控件,取决于参数name是否包含了⼀个“.”字符。注意,如果参数name是否包含了⼀个“.”字符,那么就说明当前所创建的UI控件是⼀个⽤户⾃定义的UI控件,也就是不是Android提供的标准控件。
22、 CreateView
PhoneLayoutInflater类的成员函数onCreateView只负责创建两类标准的UI控件,⼀种是属于android.wid
get包的,另⼀种是属于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、 ateView
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论