为什么使用findOne(100)查找跳转页面后的一个按钮需要1000ms以上?并且我应该怎么指定查找区域范围,这样是否能更快速找到这个按钮?

已存档
ltknnk6lvw · 2 个月前
第 1 条补充
·
2 个月前

因为我肉眼看到按钮已经出现至少一秒才打印找到按钮,这是为什么?这个时候页面已经加载完成了,但是并没有第一时间找到按钮

第 2 条补充
·
2 个月前

我看到有人提前校准,但是校准的范围是两个数值,他是获取控件的什么数值然后去查找按钮吗?这样是否会更快?那两个数值是什么?

回答

Hamibot AI
1
· 2 个月前

在 Hamibot 的控件查找机制中,findOne(100) 设置的 100ms 是等待控件出现的总超时时间。但是,如果目标控件没有立即出现,Hamibot 会持续尝试查找,直到达到指定的超时时间。因此,如果你观察到实际耗时超过 1000ms,可能是因为以下原因:

原因分析

  1. 页面跳转延迟:页面跳转后需要一定时间加载控件,而 findOne(100) 的等待时间较短,可能导致函数在控件尚未出现前就超时返回 null。
  2. 界面刷新缓慢:部分应用在跳转后需要更多时间渲染界面,导致控件未及时出现在 UI 树中。
  3. 深度优先搜索(DFS)影响findOne() 使用 DFS 算法遍历控件树,如果目标控件位于较深的层级或控件树复杂,会导致查找速度变慢。

如何优化控件查找效率?

1. 延长超时时间

为了确保控件有足够的时间加载,你可以将 findOne() 的超时时间设置得更长,例如:

var button = text("按钮文本").findOne(5000); // 等待最多 5 秒钟

2. 限制查找区域范围

Hamibot 提供了 boundsInside(left, top, right, bottom) 方法,可以限制控件查找的区域范围,从而提高查找效率。通过缩小查找范围,减少不必要的控件扫描,加快定位速度。示例代码如下:

// 指定查找区域为屏幕中间的部分区域
var button = text("按钮文本")
    .boundsInside(0, 500, 1080, 1500) // 左上角 (0, 500),右下角 (1080, 1500)
    .findOne(5000);

请根据实际屏幕分辨率调整 boundsInside() 的参数值。

3. 使用 waitFor() 替代 findOne()

如果你希望脚本在控件出现后立即执行操作,而不是反复查找,可以使用 waitFor() 函数。该方法会持续等待直至控件出现,且性能优于 findOne()

text("按钮文本").waitFor(); // 等待控件出现
var button = text("按钮文本").findOnce();

4. 优化控件选择器

尽量使用唯一标识控件的属性,如 id()desc(),而非 text(),因为文本内容可能重复或被多语言支持干扰。示例:

var button = id("com.example:id/unique_button").findOne(5000);

总结

  • 控件查找速度受页面加载时间和查找算法的影响。
  • 使用 boundsInside(left, top, right, bottom) 可以限制查找区域,提高效率。
  • 对于复杂的控件结构,建议优化选择器条件并合理设置超时时间。

如果以上方法仍无法满足需求,可以发送邮件到 support@hamibot.cn 获取进一步技术支持。


补充回答 1

这种情况通常与 Hamibot 的控件查找机制和页面刷新频率有关。即使你肉眼看到按钮已经出现,Hamibot 也不能立即识别它,原因如下:


1. 控件树更新延迟

  • Android 系统并不是实时将 UI 更新到控件树中,而是有一定的刷新间隔(通常是 16ms 左右)。
  • requestScreenCapture() 和控件查找依赖的 UiAutomator 服务获取的是系统快照版本的 UI 树,并非实时画面。
  • 页面虽然看起来加载完成,但控件树可能还没有完全同步新的状态。

2. 控件查找是异步过程

  • 每次调用类似 text("按钮").findOne() 时,Hamibot 都会触发一次完整的 UI 树检索和匹配操作。
  • 这个过程需要一定时间(几毫秒到几十毫秒),尤其是在控件结构复杂或嵌套较多的情况下。
  • 即使控件已经在界面上渲染出来,也需要等到 Hamibot 下一次扫描 UI 树才能发现它。

3. 查找策略是深度优先搜索(DFS)

  • findOne() 使用 DFS(深度优先搜索)遍历控件树。
  • 如果目标控件位于较深层级或在控件树靠后的位置,就可能出现“先看到再找到”的情况。
  • 控件在视觉上出现后仍需等待若干轮查找才会被命中。

4. 脚本执行和 UI 刷新不同步

  • 脚本逻辑是线性的,而 Android 的界面更新是非连续的。
  • 在跳转后的瞬间调用 findOne(),可能刚好错过了当前帧的 UI 快照。
  • 建议使用 waitFor() 或添加短暂停顿(如 sleep(500))来确保 UI 完成刷新后再开始查找。

推荐优化方法

✅ 方法一:配合 waitFor()

// 文档地址 https://docs.hamibot.com/
text("按钮文本").waitFor(); // 自动阻塞直到控件出现
var button = text("按钮文本").findOnce();

waitFor() 内部已做了高效轮询和 UI 更新监听,比 findOne(timeout) 更稳定。

✅ 方法二:限制查找区域提高效率

// 文档地址 https://docs.hamibot.com/
var btn = text("按钮文本")
    .boundsInside(0, 800, 1080, 1920) // 限定屏幕底部区域
    .findOne(5000);

✅ 方法三:适当添加等待时间

// 文档地址 https://docs.hamibot.com/
sleep(800); // 给 UI 充足的时间完成渲染
var btn = text("按钮文本").findOne(3000);

总结

即使你肉眼看到控件已经显示,Hamibot 仍需等待系统更新 UI 树、进行控件查找和匹配,这中间存在一定的延迟。使用 waitFor() 是最直接有效的方法,也可以通过 boundsInside() 缩小查找范围来加快定位速度。

如果你有更多关于控件查找性能的问题,欢迎继续提问。


补充回答 2

在 Hamibot 的控件查找中,有些用户会使用“校准”技巧来优化控件定位的效率和准确性。你提到的“两个数值”通常是指屏幕坐标的 X 轴 和 Y 轴 的范围值,用于限定查找区域。


🧠 他获取的是控件的什么数值?

这两个数值通常是通过以下方式获取的:

var bounds = text("目标控件").findOne().bounds();
toast("left: " + bounds.left + ", top: " + bounds.top + ", right: " + bounds.right + ", bottom: " + bounds.bottom);

控件的 bounds() 属性返回一个 Rect 对象,包含四个值:

  • left: 控件左侧距离屏幕左边的像素值
  • top: 控件顶部距离屏幕上边的像素值
  • right: 控件右侧距离屏幕左边的像素值
  • bottom: 控件底部距离屏幕上边的像素值

用户进行“校准”的时候,通常会记录某个控件所在的 坐标范围(例如 left、right),然后用这个范围去限定后续查找的区域。


🔍 示例:使用两个数值进行校准查找

假设你知道按钮出现在屏幕水平方向(X轴)大约在 300~500 像素之间:

// 文档地址 https://docs.hamibot.com/
var btn = text("按钮文本")
    .boundsInside(300, 0, 500, device.height) // 只在 X 轴 300~500 区域内查找
    .findOne(3000);

这样可以缩小查找范围,避免全屏扫描,提高查找速度。


⚡ 这样是否会更快?

是的,使用 boundsInside() 缩小查找区域能显著提升控件查找效率,特别是在以下情况:

  • 页面结构复杂,嵌套深
  • 控件数量多,重复文本或描述
  • 查找的目标控件位置固定或有规律可循

因为 Hamibot 不需要遍历整个 UI 树,而是只检查指定区域内符合条件的控件。


✅ 总结

  • “两个数值”通常是指控件在屏幕上的 X轴 或 Y轴 的起始与结束位置
  • 用户通过 bounds() 获取控件的位置后,再使用 boundsInside(left, top, right, bottom) 来限定查找范围
  • 使用这种方式可以加快查找速度、减少误匹配,提高脚本稳定性

如果你需要进一步自动化校准流程,也可以先运行一次完整查找,保存控件位置,后续查找都基于该范围,这样既准确又高效。

ℹ️ 本回答由 AI 生成,内容仅供参考