专栏文章 一招轻松提高遍历 pocoUI 树的效率

fishfish-yu · January 15, 2020 · 645 hits

“以下文章来源于“遍历pocoUI树的效率”,作者saint_228。”

前言

在Poco的实际应用过程中,我们可能会经常遇到需要遍历pocoUI树的情况。整个项目的UI树,体积有可能非常庞大。

举个例子,将一个项目完整的UI树以字典的形式存储在txt文本里,容量也可能高达几百K。

image

所以在需要遍历UI树或者进行复杂选择的情况下,我们需要用一些方法,来提高遍历UI树的效率。下文将介绍几种遍历UI树的方法以及其遍历效率。

(PS:可以使用如下代码抓取页面中的所有元素)

poco = poco(...)
ui = poco.agent.hierarchy.dump()

方法1:offspring()

poco树中的各种控件都有其属性,下面就以项目中“UICarmeraRoot”这个对象为例:

image

查询UI树里,最偷懒的方法就是直接生成一个全树的实例,然后取其所有后代,再在其后代中逐个查找符合条件的属性对应的对象。
示例代码为:

uioffspring=poco("UIRoot(Clone)").offspring()
for x in uioffspring:
if x.attr("name") == 'UICameraRoot':
print(x.get_text())
print('查找控件过程结束')
break
else :
print("没找到")

从图中我们可以知道这段代码执行所需时间为:144秒。

image

分析一下,瓶颈应该出在if x.attr("name") == 'UICameraRoot'这句:

image

每次对poco实例的属性进行操作,都需要重新生成一个dump,这非常耗费资源。
除非在之后的业务逻辑里要对offspring()进行不可同步的操作,否则不建议采取这种方法。

方法2:offspring()指定参数

offspring()方法里跟指定参数,可以将dump操作缩减为1次。大大提升效率。
示例代码如下:

ui_node_name = poco("UIRoot(Clone)").offspring(name='UICameraRoot')
print('查找控件XX结束')

代码精简,效率也提升了几十倍。花费了4.8秒就从整个UI树中查询到了我们需要的控件。

image

方法3:freeze()

poco还给我们提供了freeze()方法,即冻结UI,能再次加快查询效率。

image

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')

结果如下:

image

image

可以看出两种算法的耗时相差无几。且都低于对poco实例的操作耗时。

我们从原理来理解一下:冻结UI其实就是将当前界面的层次结构包括所有UI的属性信息抓取下来,然后存到内存里。在跟UI交互时,就直接从内存里读取UI属性,而不用再发送rpc请求到game/app里去操作UI。

好处就是一次抓取(消耗几百毫秒),可以使用多次,读取UI属性几乎不消耗时间,效率极高。

但是坏处在于,你需要手动处理UI同步;如果抓取了层次结构后,某个UI控件位置发生了变化,此时如果仍然点击这个UI的话,就会点击到原来的位置上,而不是最新的位置,这很容易导致奇怪的测试结果;并且使用完最好也尽快释放,否则会占据大量的内存资源。

小结

  1. 除非需要操作整个UI树实例里的不同对象,否则尽量不要读取全树
  2. 读全树的效率比读单个控件的效率低2个数量级。
  3. freeze()的效率极高。但需要手动刷新

大家需要根据自己项目的实际情况,来选取合适的遍历UI树的方法。

关注下方公众号,可以查看更多往期教程;回复“交流群”即可加入我们的测试开发官方交流群

No Reply at the moment.
需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up