无法对AccessibilityNodeInfo执行操作:密封实例报错求助
问题重现
执行无障碍操作时触发如下致命异常:
致命异常:main 进程:com.example.acxessibility,进程ID:18375
java.lang.IllegalStateException:无法对密封实例执行操作。位于
android.view.accessibility.AccessibilityNodeInfo.enforceNotSealed(AccessibilityNodeInfo.java:3743)
异常触发代码:
Node.performAction(AccessibilityNodeInfo.AccessiblityAction.ACTION_SHOW_ON_SCREEN.getId());
(注:代码中AccessiblityAction存在拼写错误,正确应为AccessibilityAction)
核心原因
AccessibilityNodeInfo被系统标记为**密封(sealed)**后,所有修改、操作类调用都会触发该异常。通常是以下场景导致:
- 复用了已被系统回收/标记为不可用的旧NodeInfo实例
- 持有NodeInfo实例时间过长,系统已完成对它的生命周期管理
- 调用
recycle()回收实例后,再次尝试操作
解决方案
不要复用旧NodeInfo实例,每次操作重新获取
避免缓存NodeInfo长期使用,每次需要操作目标节点时,通过AccessibilityService.getRootInActiveWindow()重新获取根节点,再遍历定位目标节点。例如:AccessibilityNodeInfo root = getRootInActiveWindow(); if (root != null) { // 遍历找到目标节点 AccessibilityNodeInfo targetNode = findTargetNode(root); if (targetNode != null && !targetNode.isSealed()) { targetNode.performAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_ON_SCREEN.getId()); targetNode.recycle(); // 用完及时回收 } root.recycle(); }操作前检查实例状态(API 26+)
API 26及以上提供isSealed()方法,可直接判断实例是否可用:if (node != null && !node.isSealed()) { node.performAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_ON_SCREEN.getId()); }低版本可通过捕获异常的方式处理,避免崩溃。
及时回收NodeInfo实例
每次使用完NodeInfo后,务必调用recycle()释放资源,避免系统提前密封实例,同时也能减少内存占用。修正代码拼写错误
代码中AccessiblityAction的拼写少了字母e,正确类名为AccessibilityAction,拼写错误可能导致其他潜在问题。
内容的提问来源于stack exchange,提问作者akash yadav

