您的位置:首页 > 其它

老李推荐:第14章8节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-获取控件列表并建立控件树 3

2016-02-24 16:19 267 查看
那么我们就往下看下剩余的控件属性是怎么给解析出来的,loadProperties这个方法有点长,我们把它分看来慢慢分析,先看第一部分: 168 private void loadProperties(String data) { 169 int start = 0; 170 boolean stop; 171 do { 172 int index = data.indexOf('=', start); 173 Property property = new Property(); 174 property.name = data.substring(start, index); 175 176 int index2 = data.indexOf(',', index + 1); 177 int length = Integer.parseInt(data.substring(index + 1, index2)); 178 start = index2 + 1 + length; 179 property.value = data.substring(index2 + 1, index2 + 1 + length); 180 181 this.properties.add(property); 182 this.namedProperties.put(property.name, property); 183 184 stop = start >= data.length(); 185 if (!stop) { 186 start++; 187 } 188 } while (!stop); ... } 代码14-8-9 ViewNode-loadProperties-获取控件属性 看这段代码之前还是请回到“图13-6-1 NotesList控件列表”中重温一下一个控件的每个属性名和值是怎么组织起来的:android.widget.FrameLayout@41901ab0 drawing:mForeground=4,nullpadding:mForegroundPaddingBottom=1,0 padding:mForegroundPaddingLeft=1,0padding:mForegroundPaddingRight=1,0 padding:mForegroundPaddingTop=1,0drawing:mForegroundInPadding=4,true measurement:mMeasureAllChildren=5,falsedrawing:mForegroundGravity=3,119 events:mLastTouchDownTime=1,0 events:mLastTouchDownY=3,0.0 events:mLastTouchDownX=3,0.0 events:mLastTouchDownIndex=2,-1 mGroupFlags_CLIP_CHILDREN=3,0x1 mGroupFlags_CLIP_TO_PADDING=3,0x2 mGroupFlags=7,2244691 layout:mChildCountWithTransientState=1,0 focus:getDescendantFocusability()=24,FOCUS_BEFORE_DESCENDANTS drawing:getPersistentDrawingCache()=9,SCROLLING drawing:isAlwaysDrawnWithCacheEnabled()=4,true isAnimationCacheEnabled()=4,true drawing:isChildrenDrawingOrderEnabled()=5,false drawing:isChildrenDrawnWithCacheEnabled()=5,false bg_=4,null layout:mLeft=1,0 measurement:mMeasuredHeight=3,690 measurement:mMeasuredWidth=3,480 measurement:mMinHeight=1,0 measurement:mMinWidth=1,0 drawing:mLayerType=4,NONE padding:mPaddingBottom=1,0 padding:mPaddingLeft=1,0 padding:mPaddingRight=1,0 padding:mPaddingTop=1,0 mID=10,id/content mPrivateFlags_DRAWING_CACHE_INVALID=3,0x0 mPrivateFlags_DRAWN=4,0x20 mPrivateFlags=11,-2130703184 layout:mRight=3,480 scrolling:mScrollX=1,0 scrolling:mScrollY=1,0 layout:mBottom=3,800我们就以其中的一个属性”layout:mBottom=3,800”做为例子来解析一下它的格式:等号之前:控件属性名称,它是由两部分组成的,用冒号隔开,冒号之前代表该属性的类型,后面是属性的名称。实例中是”layout:mBottom”,其中layout代表这个是一个布局类的属性,也属于属性名的一部分

等号之后逗号之前:属性值的字节长度,在这里是3,因为后面的属性值800做为字串的话刚好占了3个字节

逗号之后:属性值,在这里是800,代表这个控件的最下面部分的Y坐标是800

知道属性的格式就好去理解代码14-8-7所做的事情了:首先外层一个while循环去分析每一个属性

找到等号的位置,然后取出等号之前的控件属性名字

找到逗号的位置,然后取出等号之后到逗号之前的控件属性值的长度

找到控件属性值的位置和控件属性值结束的位置,然后取出它们之间的控件属性值

把该控件属性加入到properties列表里面保存起来

把该控件属性名称和属性值加入namedProperties这个映射里面保存起来

进入下一个循环解析下一个属性值,直到一行控件信息的长度尽头就跳出循环

分析完loadProperties的第一部分后,我们继续往下看: private void loadProperties(String data) { ... Collections.sort(this.properties, new Comparator() {   public int compare(ViewNode.Property source, ViewNode.Property destination) {   return source.name.compareTo(destination.name); } }); ... 代码14-8-10 ViewNode-loadProperties-属性列表排序 这里如果你对java熟悉的话其实很简单,就是根据控件属性的名字对properties列表进行一次排序而已。如果你对java不熟悉的话,那就要先去查下Collections.sort这个方法是怎么回事了。顾名思义它提供的是对一个集合List的排序功能,但是根据什么来排序呢?这里就涉及到两个概念了:Comparator接口:提供的是一个接口,用户应该去实现该接口来提供列表中两个元素的对比功能

另外一个是匿名类:上面的new Comparator的写法就是建立一个实现了Comparator接口的匿名类

对于匿名类,如果上面的代码做转换成以下应该会让你清晰多了。比如我们先定义一个实现了Comparator的类: public class PropertyComparator implements Comparator{ public int compare(ViewNode.Property source, ViewNode.Property destination) { return source.name.compareTo(destination.name); }
然后把上面的排序部分调用改成: Comparator propComp = new PropertyComparator(); Collections.sort(this.properties, propComp);
这样应该就好理解多了,如果还不清楚的话那我建议你还是先去学习下java的基本知识再返回来往下看。 在获取了控件属性和对属性排好序之后,我们继续往下分析loadProperties方法的第三部分: 168 private void loadProperties(String data) { ... 206 this.height = (this.namedProperties.containsKey("getHeight()") ? getInt("getHeight()", 0) : getInt("layout:getHeight()", 0)); 207 208
209 this.scrollX = (this.namedProperties.containsKey("mScrollX") ? getInt("mScrollX", 0) : getInt("scrolling:mScrollX", 0));
210
211
212 this.scrollY = (this.namedProperties.containsKey("mScrollY") ? getInt("mScrollY", 0) : getInt("scrolling:mScrollY", 0));
... } 代码14-8-11 ViewNode-loadProperties-保存获取的属性 这里虽然代码很长,但是每一行做的事情基本上都一样,都是很简单的去刚才建立好的namedProperties映射里面根据属性名称取得对应的属性值,然后保存到ViewNode对应的变量里面去。但注意并不是所有的属性都会取出来另外存储,只有那些常用的属性会这样子做。 168 private void loadProperties(String data) { ... 254 for (String name : this.namedProperties.keySet()) { 255 int index = name.indexOf(':'); 256 if (index != -1) { 257 this.categories.add(name.substring(0, index)); 258 } 259 } 260 if (this.categories.size() != 0) { 261 this.categories.add("miscellaneous"); 262 }
263 } 代码14-8-12 ViewNode-loadProperties-组建控件属性类型列表上面我们有提过,控件的属性名称是有两部分组成的,冒号之前的是属性的类型,比如上面提到的layout类型。以上代码所做的事情就是找到一个属性的冒号的位置,然后把之前的那部分属性类型字串给取出来保存到properties这个集合里面。
106 public Set<String> categories = new TreeSet();
代码14-8-13 ViewNode-categories-控件属性类型集合 到了现在整个控件树以及控件的建立过程就算分析完成了,我们这里稍稍总结下整个流程:测试脚本在调用HierarchyViewer类的findViewById方法的时候首先会去调用ViewNode的 loadWindowData方法

该方法会先去ViewServer发送DUMP命令来获得所有控件信息

获得所有控件信息后会调用parseViewHierarchy方法去创建好整棵ViewNode组成的控件树
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  测试