Uiautomator-注入事件原理

这一篇文章我们会通过分析UiDevice的pressHome这个方法来分析UiAutomator是如何注入事件的,下一篇文章会描述如何获取控件,敬请期待。

 

1. UiObject.pressHome顺序图

首先我们看一下我手画的非规范的顺序图,从中我们可以看到pressHome这个动作究竟需要和多少个类进行交互,以及它们是怎么交互的。

 

Uiautomator-注入事件原理

2.这些类是什么时候初始化的

在我们编写测试用例脚本的时候我们不会对以上所有的类进行初始化,包括UiObject对象都是通过直接在脚本中调用父类UiAutomationTestCase的getUiDevice()这个方法来获得的。其实这些都是在uiautomator运行时由RunTestCommand类的start()这个方法进行初始化的,具体请看《UIAutomator源码分析之启动和运行》的 3.6章节“初始化UiDevice和UiAutomationBridge“,这里就不做累述。我们这里会看下在初始化UiAutomatorBridge的时候是如何把QuneryControoler和InteractionController一并初始化了的,具体请看UiAutomatorBridge的构造函数:

Uiautomator-注入事件原理

 

 

3. 代码跟踪

首先看UiDevice的pressHome方法:


220行:

  • 获得UiDevice对象保存的UiAutomatorBridge对象。着两个对象都是在运行时初始化的,不清楚的话请翻看上面提到的文章
  • 通过UiAutomatorBridge对象获得上面章节初始化的InteractionController对象
  • 调用InteractionController对象的sendKeyAndWaitForEvent方法,里面参数关键是第一个keycode和第二个eventType
    • keycode:代表我们要注入的是按下哪个按键的事件,比如这里我们是KEYCODE_HOME
    • eventType:代表我们注射了该事件后预期会获得窗口返回来的哪种AccessibilityEvent类型,比如我们这里是TYPE_WINDOW_CONTENT_CHANGE

进入InteractionController类的sendKeyAndWaitForEvent:

Uiautomator-注入事件原理

 

代码中创建了一个Runnable的线程,线程里面run重写方法要做的事情就是去做注入事件的事情,那么为什么我们不直接去调用事件而需要创建一个线程了,这是因为我们在注入完事件之后还要去等待我们上面定义的预期的eventType是否有出现来判断我们的事件注入究竟是否成功,这个就是204行runAndWaitForEvents做的事情。但我们这里还是先看下线程中是如何注入事件的:

Uiautomator-注入事件原理

 

再跟踪到UiAutomatorBridge对象:

Uiautomator-注入事件原理

 

可以看到最终还是通过UiAutomation来注入事件的,和我们的预期是一致的。

我们继续看InteractionController中真正执行注入事件线程的runAndWaitForEvents方法:

Uiautomator-注入事件原理

 

代码又跳到了UiAutomatorBridge这个类

Uiautomator-注入事件原理

 

最终把要执行的runnable执行注入事件的线程command和我们预期事件发生后返回来的窗口事件filter以及超时timeoutMillis传进去,UiAutomation就会和AccessibilityService进行交互以注入事件并且等待预期AccessibilityEvent发生或者超时返回。至于UiAutomation是如何和AccessibilityService交互的,这就超出了这个系列文章的范畴了。也许今后有充裕的时间的话我们再来深入去了解分析它。

参考博客:https://blog.****.net/zhubaitian/article/details/40541927