(注意:本文基于UI Automator测试框架版本为2.2.0)
前言
UiDevice中与UiWatcher相关的API共计6个,注册与反注册UiWatcher功能非常重要,只有注册成功的UiWatcher,才能起到监听控件的作用。UiWatcher是一个interface,每一个实现UiWatcher的类,都表示一种具备监听控件的能力,正因如此,每当我们在插桩测试过程中,发现代表控件的UiObject、UiObject2对象出现找不到的情况时,就会自动通知每个注册的UiWatcher,UiWatcher收到通知后,会回调实现的checkCondition()方法,我们可以在UiWatcher实现类中的checkConditioni()中编写一些找不到控件的处理逻辑。UiWatcher自定义的处理逻辑只要完善,即可以确保测试项目的绝对稳定性(妥妥的),比如我们可以在UiWatcher中处理弹窗(罪魁祸首),处理网络状态以及你能想到可以做的任何影响控件被找到的逻辑,本篇文章我们学习一下UiWatcher是如何注册到UiDevice中的,又是如何从UiDevice中取消注册的,这两个功能是在UiDevice中的registerWatcher()方法、removeWatcher()方法实现的!你平时可以注册局部的UiWatcher、也可以注册全局的UiWatcher,局部的UiWatcher只对特定的控件生效,全局的UiWatcher对所有控件生效!
registerWatcher()方法用于注册UiWatcher
removeWatcher()方法用于反注册UiWatcher
registerWatcher()方法分析
用于注册UiWatcher的方法,该方法位于UiDevice类中,接受两个参数,第一个参数是一个String对象,表示注册UiWatcher对象的名字,第二个参数为注册的UiWatcher对象,每个UiWatcher对象表示一个Ui观察者(控件监听者)
public void registerWatcher(String name, UiWatcher watcher) {
Tracer.trace(name, watcher);
if (mInWatcherContext) {
throw new IllegalStateException("Cannot register new watcher from within another");
}
mWatchers.put(name, watcher);
}
1、追踪线程堆栈信息,用于Debug
将传入的参数name与watcher传入Tracer的静态方法trace()中,这个方法会记录线程的堆栈信息
2、防止在UiWatcher中再次注册UiWatcher
判断标志位mInWatcherContext,它是UiDevice对象持有的一个boolean型标志位,true表示正在处于UiWatcher的处理逻辑中,false则表示不在UiWatcher处理逻辑中,使用mInWatcherContext标志位可以防止我们在UiWatcher的checkForCondition()方法中再去注册一个新的UiWatcher对象,即不允许从另一个观察者中注册新的观察者,如果我们违反规则就会得到一个IllegalStateException异常对象。其实这个mInWatcherContext标志位还有另外一个作用,它还可以防止UiWatcher的checkForCondition()方法被连续多余的触发,在触发UiWatcher的方法runWatchers()中也同时使用了该标志位,这个我们后面再了解。(mInWatcherContext的两个作用)
3、注册UiWatcher到一个容器中
通过上面的检查,到了真正注册UiWatcher对象的位置,通过mWatchers的put()方法将name与watcher一起注册。那么mWathcers是什么呢?mWatchers是UiDevice对象持有的一个HashMap对象,此时的name作为key,watcher则是作为value,只要把UiWatcher保存到容器中,即表示成功注册一个UiWatcher!
removeWatcher()方法分析
用于反注册UiWatcher的方法,该方法位于UiDevice类中,传入参数表示UiWatcher的名字
public void removeWatcher(String name) {
Tracer.trace(name);
if (mInWatcherContext) {
throw new IllegalStateException("Cannot remove a watcher from within another");
}
mWatchers.remove(name);
}
注册的UiWatcher对象都被保存到UiDevice对象持有的一个HashMap对象mWatchers中了,反注册UiWatcher,只需要从HashMap对象中删除对应的元素即可,我们看下具体的实现过程
1、追踪线程堆栈信息,用于Debug
首先也是线程堆栈的跟踪,为了方便调试
2、防止在UiWatcher中反注册一个UiWatcher
标志位mInWatcherContext,不允许在UiWatcher中移除一个UiWatcher,否则会得到一个IllegalStateException对象
3、反注册UiWatcher
从UiDevice对象持有的HashMap对象mWatchers中执行删除元素,为HashMap的remove()方法传入表示UiWatcher名字的key对象name即可!
总结
1、注册UiWatcher功能:将UiWatcher对象的引用保存在UiDevice对象持有的HashMap对象mWatchers中,完成UiWatcher的注册
2、反注册UiWatcher功能:从UiDevice对象持有的HashMap对象mWatchers中删除元素,完成UiWatcher的反注册
3、每个UiWatcher对象保存在HashMap对象中,注册UiWatcher使用的key对象统一保管,这样才方便随时根据需求情况注册与取消注册UiWatcher对象
4、UiWatcher的checkForCondition()方法中不能再进行UiDevice对象的注册与反注册,否则会得到一个IllegalStateException对象!
以下截图是标志位mInWatcherContext唯一赋值为true的位置,说明此时处于UiWatcher执行过程中,runWatchers()方法也位于UiDevice中,它的功能是回调所有已注册的UiWatcher的checkForCondition()方法!