是否有一个原因?可访问性事件是否不可靠..?
我发现当一个事件被触发时,你更有可能误解TYPE_WINDOW_CONTENT_CHANGED
,而不是它没有被触发或持续捕获。例如,此特定事件不会在屏幕刷新时触发,只会在新窗口内容时触发。应用程序开发人员可以选择在其 Activity 上重新绘制内容,而不是启动新的 Activity。在这种情况下,从用户的角度来看,窗口内容已经改变,然而,在应用程序的后端,他所发生的只是绘制了新的视图。
thread.sleep 无济于事 - 因为看起来 AccessibilityEventNodeInfo 更像是一个快照而不是对 UI 的实时访问?有什么办法吗?
这也是为什么事件源中缺少元素的解释。您在绘制动态元素之前收到事件。因此,启动了一个新的 Activity,并使用新内容进行了初始化,但是,应用程序可能会进入等待某种类型的网络/REST 资源的模式。在这些资源到来之前,事件被触发,然后不久之后新的内容被绘制。因此,在您看来,您获得了不完整的内容,但真正发生的是您在事件触发时获得了完整的内容。你的 thread.sleep 方法工作得很好。然而,在你睡眠之后,你不能检查 event.getSource() 的值,睡眠不会改变传递给这个函数的内容。相反,你想睡觉,然后爬取整个视图层次结构以找到您想要的信息。休眠然后使用
getRootInActiveWindow();
代替
event.getSource();
是否有任何线索可以帮助我从我看到的 AccessibilityEventNodeInfo 实例中确定滚动位置?
是和不是。不,无障碍服务无法检测滚动条的位置。但是,您可以通过执行以下操作来检测滚动事件的大致位置:
private float getScrollPosition(AccessibilityEvent event) {
final AccessibilityRecordCompat record = new AccessibilityRecordCompat(event);
final int itemCount = event.getItemCount();
final int fromIndex = event.getFromIndex();
// First, attempt to use (fromIndex / itemCount).
if ((fromIndex >= 0) && (itemCount > 0)) {
return (fromIndex / (float) itemCount);
}
final int scrollY = record.getScrollY();
final int maxScrollY = record.getMaxScrollY();
// Next, attempt to use (scrollY / maxScrollY). This will fail if the
// getMaxScrollX() method is not available.
if ((scrollY >= 0) && (maxScrollY > 0)) {
return (scrollY / (float) maxScrollY);
}
// Finally, attempt to use (scrollY / itemCount).
// TODO(alanv): Hack from previous versions -- is it still needed?
if ((scrollY >= 0) && (itemCount > 0) && (scrollY <= itemCount)) {
return (scrollY / (float) itemCount);
}
return 0.5f;
}
这直接来自 Google 的 TalkBack 代码。您可以在 EyesFree 项目的 ScrollFormatter.java 中找到它。这不是一个理想的解决方案。如果事件恰好来自大型布局(就像 chrome 中的网页经常发生的那样),那么对于大部分滚动,您最终会得到相同的结果。但是,API 不支持比这更精确的任何东西,因此如果您想知道大致的滚动位置,这是一个必要的技巧。我认为即使使用可用的 API,也可以对这种方法进行重大改进,尽管这需要一些工作。