UiAutomator源码分析之获取控件信息

根据上一篇文章《》开始时提到的计划,这一篇文章我们要分析的是第二点:

    <李>如何获取控件信息李
我们在测试脚本中初始化一个UiObject的时候通常是像以下这个样子:“代码”类UiObject appsTab=new UiObject(新UiSelector ()。text (“Apps"));appsTab.click () 那么这个过程发生了什么呢?这就是我们接下来要说的事情了。

1。获取控件信息顺序图

这里依然是一个手画的不规范的顺序图,描述了UiObject尝试获得一个控件的过程中与相关的类的交互,这些类的关系在《》中已经进行了描述。 UiAutomator源码分析之获取控件信息”> <br>这里整一个过程并不复杂,简单说明下就这几点:<ul> <李> UiObject对象几经周折通过不同的类最终联系上UiAutomation,然后通知UiAutomation对象它想取得当前活动窗口的所有元素的AccessibilityNodeInfo类型的根节点</李> <李> AccessibilityNodeInfo代表了屏幕中控件元素的一个节点,同时它也拥有一些成员方法可以以当前节点为基础来获得其他目标节点。可以把屏幕上的节点想像成是通过类& # 20284;xml的& # 26684;式组织起来的,所以一旦知道根节点和由选择子UiSelector指定的目标控件信息,我们就可以遍历整个窗口控件</李> <李> QueryController对象获得之根节点后,就是调用tranlateCompoundSelector这个方法来遍历窗口所有控件,直到找到选择子UiSelector指定的那个控件为止。</李> <李>注意一个AccessibilityNodeInfo只代表一个控件,遍历的时候一旦需要下一个控件的信息是必须要再次通过UiAutomation去获取的。</李> </ul> <h2> 2。触发控件查找真正发生的地方</h2> <p>在我没有去分析uiautomator的源代码之前,我一直以为空间查找是在通过UiSelector初始化一个UiObject的时候发生的:</p> <p> </p> <pre的名字==癹ava”>“代码”类UiObject appsTab=new UiObject(新UiSelector ()。text (“Apps")); </pre> <br>这让我有一种先入为主的感觉,一个控件对象初始化好后应该就已经得到了该控件所代表的节点的所有信息了,但看了源码后发现事实并非如此,以上所做的事情只是以一定的& # 26684;式准备好UiSelector选择子而已,真正触发uiautomator去获取控件节点信息的是在触发控件事件的时候,比如:<p> </p> <p> </p> <pre的名字==癹ava”>“代码”类appsTab.click () </pre>我们进入到代表一个控件的UiObject对应的操作控件的方法去看下就清楚了,以上面的点击为例:<p> </p> <p> </p> <pre的名字==癹ava”>“代码”类公共布尔单击()/* *//* */抛出UiObjectNotFoundException/* */{/* 389 */示踪剂。跟踪(新对象[0]);/* 390 */AccessibilityNodeInfo节点=findAccessibilityNodeInfo (this.mConfig.getWaitForSelectorTimeout ());/* 391 */(节点==null){/* 392 */抛出新的UiObjectNotFoundException (getSelector () .toString ());/* */}/* 394 */矩形矩形=getVisibleBounds(节点);/* 395 */返回getInteractionController () .clickAndSync (rect.centerX (), rect.centerY (), this.mConfig.getActionAcknowledgmentTimeout ());/* */}</pre>正290行式的调用触发uiautomator去调用UiAutomation去获取到我们想要的控件节点AccessibilityNodeInfo信息的。<p> </p> <p> <br> </p> <h2> 3。获得根节点</h2> <p>下面我们看下uiautomator是怎么去获取到代表窗口所有控件的根的根节点的,我们进入UiObject的findAccessibilityNodeInfo这个方法:</p> <p> </p> <pre的名字==癹ava”>“代码”类/* */保护AccessibilityNodeInfo findAccessibilityNodeInfo(长超时)/* */{/* 164 */AccessibilityNodeInfo节点=零;/* 165 */长startMills=SystemClock.uptimeMillis ();/* 166 */长currentMills=0 l;/* 167 */(currentMills & lt;=超时){/* 168 */节点=getQueryController () .findAccessibilityNodeInfo (getSelector ());/* 169 */(节点!=null){/* */休息;/* */}/* *//* 173 */UiDevice.getInstance () .runWatchers ();/* *//* 175 */currentMills=SystemClock.uptimeMillis ()——startMills;/* 176 */如果超时祝辞0 l) {/* 177 */SystemClock.sleep (1000 l);/* */}/* */}/* 180 */返回节点;/* */}</pre> UiObject对象会首先去获得一个QueryController对象,然后调用该对象的findAccessibilityNodeInfo同名方法:<p> </p> <p> </p> <pre的名字==癹ava”>“代码”类/* */保护AccessibilityNodeInfo findAccessibilityNodeInfo (UiSelector选择器、布尔isCounting) {/* *//* 143 */this.mUiAutomatorBridge.waitForIdle ();/* 144 */initializeNewSearch ();/* *//* 146 */如果(调试){/* 147 */日志。d (LOG_TAG,“搜索:“;+选择器);/* */}/* 149 */同步(this.mLock) {/* 150 */AccessibilityNodeInfo rootNode=getRootNode ();/* 151 */如果(rootNode==null){/* 152 */日志。e (LOG_TAG,“不能继续当根节点为空。流产searchUiAutomator源码分析之获取控件信息