AirtestProject 一招轻松提高遍历 pocoUI 树的效率
“以下文章来源于 “遍历 pocoUI 树的效率”,作者 saint_228。”
前言
在 Poco 的实际应用过程中,我们可能会经常遇到需要遍历 pocoUI 树的情况。整个项目的 UI 树,体积有可能非常庞大。
举个例子,将一个项目完整的 UI 树以字典的形式存储在 txt 文本里,容量也可能高达几百 K。
所以在需要遍历 UI 树或者进行复杂选择的情况下,我们需要用一些方法,来提高遍历 UI 树的效率。下文将介绍几种遍历 UI 树的方法以及其遍历效率。
(PS:可以使用如下代码抓取页面中的所有元素)
poco = poco(...)
ui = poco.agent.hierarchy.dump()
方法 1:offspring()
poco 树中的各种控件都有其属性,下面就以项目中“UICarmeraRoot”
这个对象为例:
查询 UI 树里,最偷懒的方法就是直接生成一个全树的实例,然后取其所有后代,再在其后代中逐个查找符合条件的属性对应的对象。
示例代码为:
uioffspring=poco("UIRoot(Clone)").offspring()
for x in uioffspring:
if x.attr("name") == 'UICameraRoot':
print(x.get_text())
print('查找控件过程结束')
break
else :
print("没找到")
从图中我们可以知道这段代码执行所需时间为:144 秒。
分析一下,瓶颈应该出在if x.attr("name") == 'UICameraRoot'
这句:
每次对 poco 实例的属性进行操作,都需要重新生成一个dump
,这非常耗费资源。
除非在之后的业务逻辑里要对offspring()
进行不可同步的操作,否则不建议采取这种方法。
方法 2:offspring() 指定参数
offspring()
方法里跟指定参数,可以将dump
操作缩减为 1 次。大大提升效率。
示例代码如下:
ui_node_name = poco("UIRoot(Clone)").offspring(name='UICameraRoot')
print('查找控件XX结束')
代码精简,效率也提升了几十倍。花费了 4.8 秒就从整个 UI 树中查询到了我们需要的控件。
方法 3:freeze()
poco 还给我们提供了freeze()
方法,即冻结 UI,能再次加快查询效率。
从freeze()
的源码可以看到,freeze()
得到的是当前 poco 实例的一个静态副本。
我们可以通过下面的方式取到freeze实例
。
poco = Poco(...)
frozen_poco = poco.freeze()
hierarchy_dict = frozen_poco.agent.hierarchy.dump()
尝试将这个freeze()
实例应用到上面的方法 1 和方法 2 中,具体应用如下:
- 将方法 1 里的
uioffspring=poco("UIRoot(Clone)").offspring()
替换为uioffspring=freeze("UIRoot(Clone)").offspring()
- 将方法 2 里的
ui_node_name=poco("UIRoot(Clone)").offspring(name='UICameraRoot')
替换为ui_node_name=freeze("UIRoot(Clone)").offspring(name='UICameraRoot')
结果如下:
可以看出两种算法的耗时相差无几。且都低于对 poco 实例的操作耗时。
我们从原理来理解一下:冻结 UI 其实就是将当前界面的层次结构包括所有 UI 的属性信息抓取下来,然后存到内存里。在跟 UI 交互时,就直接从内存里读取 UI 属性,而不用再发送 rpc 请求到 game/app 里去操作 UI。
好处就是一次抓取 (消耗几百毫秒),可以使用多次,读取 UI 属性几乎不消耗时间,效率极高。
但是坏处在于,你需要手动处理 UI 同步;如果抓取了层次结构后,某个 UI 控件位置发生了变化,此时如果仍然点击这个 UI 的话,就会点击到原来的位置上,而不是最新的位置,这很容易导致奇怪的测试结果;并且使用完最好也尽快释放,否则会占据大量的内存资源。
小结
- 除非需要操作整个 UI 树实例里的不同对象,否则尽量不要读取全树;
- 读全树的效率比读单个控件的效率低 2 个数量级。
-
freeze()
的效率极高。但需要手动刷新。
大家需要根据自己项目的实际情况,来选取合适的遍历 UI 树的方法。
关注下方公众号,可以查看更多往期教程;回复 “交流群” 即可加入我们的测试开发官方交流群