方法 "automator.scrollDown" 调用失败. length=0; index=0
方法 "automator.scrollDown" 调用失败. length=0; index=0
AutoJS6:6.6.4版本 Android 版本:10
另: 在安卓 13环境下,while(scrollDown());会无限调用,阻塞
我在 AVD 上测试了 API Level 29 (Android 10) [Q], 可以复现 automator.scrollDown 导致的 ArrayIndexOutOfBoundsException 异常.
这主要是因为 AutoJs6 的 UiObject 类中不恰当地覆写了 hashCode 方法, 当诸如 HashSet#contains 方法内部调用 UiObject 的 hashCode 方法时, 触发 AccessibilityNodeInfoCompat#getChild 在 Android 10 上的特定异常.
在源码层面, 你可以尝试去除 hashCode (以及 equals) 的覆写, 将主要逻辑放置在 isSimilar 中. 另外为了安全起见, child(Int) 方法加入索引边界检查, 例如:
open fun child(i: Int): UiObject? = when {
i >= childCount -> {
null
}
i < 0 -> when (val targetIdx = i + childCount) {
in 0 until childCount -> child(targetIdx)
else -> null
}
else -> runCatching {
// @Caution by SuperMonster003 on Jun 19, 2025.
// ! `super.getChild` may cause ArrayIndexOutOfBoundsException when `i` is out of range of [0..childCound).
// ! zh-CN: 当 `i` 超出 [0..childCount) 范围时可能导致 ArrayIndexOutOfBoundsException 异常.
// @Dubious by SuperMonster003 on Jun 19, 2025.
// ! It seems that the situation above only happens on API Level 29 (Android 10) [Q] ?
// ! zh-CN: 似乎上述情况只发生在 API Level 29 (Android 10) [Q] ?
super.getChild(i)?.let { UiObject(it.unwrap(), depth + 1, i) }
}.onFailure {
// FIXME by Stardust on May 5, 2017.
it.printStackTrace()
}.getOrNull()
}
在 Rhino 脚本层面, 目前尚无解决方案.
while(scrollDown); 无限调用, 是因为 while 的条件一直为 true.
这往往是无障碍服务 AccessibilityNodeInfo#performAction(int) 返回值的不确定性导致的.
例如 click 方法返回 true, 但实际上控件并没有响应点击操作; 同样地, scrollDown 方法返回 true, 也可能出现屏幕上可滚动控件并没有出现滚动行为的现象. 因此, 无障碍服务的行为类方法, 它们的返回值并不是完全可信的, 很多时候需要结合二次确认的方式 (如控件位置是否发生变化, 是否从屏幕上消失等) 来保证行为的执行确定性.
最后你提到的阻塞, 如果指的是 while 循环, 那么上述内容已解释其原因. 如果指的是 scrollDown 方法, 则应视为 bug.
一个简单的验证方法, console.log(scrollDown());, 检查是否出现阻塞.