Android 7系统无障碍服务(四)AccessibilityEvent 的产生与投递

Android 7系统无障碍服务(四)------AccessibilityEvent 的产生与投递

系列目录 :第一篇:全景图与架构概览 | [第二篇:AccessibilityManagerService 启动与初始化](#第二篇:AccessibilityManagerService 启动与初始化) | 第三篇:无障碍服务的注册与绑定 | [第四篇:AccessibilityEvent 的产生与投递](#第四篇:AccessibilityEvent 的产生与投递) | [第五篇:AccessibilityNodeInfo 的构建与查询](#第五篇:AccessibilityNodeInfo 的构建与查询) | [第六篇:输入事件拦截与 TouchExplorer](#第六篇:输入事件拦截与 TouchExplorer) | [第七篇:手势分发与 KeyEvent 处理](#第七篇:手势分发与 KeyEvent 处理) | 第八篇:放大镜与辅助功能特性


上一篇分析了无障碍服务从 Manifest 声明到被 AMS 绑定并就绪的全过程。服务就绪后,系统如何将 UI 变化告知它?答案就是 AccessibilityEvent。本篇完整梳理 AccessibilityEvent 从 View 层产生、经 AccessibilityManager 跨进程投递、在 AMS 中排队与调度、最终到达 AccessibilityService 的全链路。

一、AccessibilityEvent 是什么

AccessibilityEvent 是系统将 UI 变化通知无障碍服务的载体。它携带了"什么组件发生了什么变化"的上下文信息。

源码路径 :frameworks/base/core/java/android/view/accessibility/AccessibilityEvent.java

java 复制代码
public final class AccessibilityEvent extends AccessibilityRecord implements Parcelable {
    // 核心事件类型(部分)
    public static final int TYPE_VIEW_CLICKED            = 0x00000001;
    public static final int TYPE_VIEW_LONG_CLICKED       = 0x00000002;
    public static final int TYPE_VIEW_SELECTED           = 0x00000004;
    public static final int TYPE_VIEW_FOCUSED            = 0x00000008;
    public static final int TYPE_VIEW_TEXT_CHANGED       = 0x00000010;
    public static final int TYPE_WINDOW_STATE_CHANGED    = 0x00000020;
    public static final int TYPE_NOTIFICATION_STATE_CHANGED = 0x00000040;
    public static final int TYPE_WINDOW_CONTENT_CHANGED  = 0x00000800;
    public static final int TYPE_VIEW_SCROLLED           = 0x00001000;
    public static final int TYPE_ANNOUNCEMENT            = 0x00004000;
    public static final int TYPE_VIEW_ACCESSIBILITY_FOCUSED   = 0x00008000;
    public static final int TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED = 0x00010000;
    public static final int TYPES_ALL_MASK               = 0xFFFFFFFF;

    private int mEventType;
    private CharSequence mPackageName;
    private long mEventTime;
    // 继承自 AccessibilityRecord: mSourceNodeId, mWindowId, mClassName, mText 等
}

二、事件在 View 层的产生

源码路径 :frameworks/base/core/java/android/view/View.java

java 复制代码
public void sendAccessibilityEvent(int eventType) {
    if (mAccessibilityDelegate != null) {
        mAccessibilityDelegate.sendAccessibilityEvent(this, eventType);
    } else {
        sendAccessibilityEventInternal(eventType);
    }
}

private void sendAccessibilityEventInternal(int eventType) {
    if (AccessibilityManager.getInstance(mContext).isEnabled()) {
        sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType));
    }
}

public void sendAccessibilityEventUnchecked(AccessibilityEvent event) {
    if (!isShown()) return;  // 不可见 View 不发送
    onInitializeAccessibilityEvent(event);
    if (mParent != null) {
        mParent.requestSendAccessibilityEvent(this, event);
    }
}

两个过滤点:isEnabled() 全局开关检查 + isShown() 可见性检查。

典型触发场景:

  • TYPE_VIEW_CLICKED → View.performClick() 中触发
  • TYPE_VIEW_TEXT_CHANGED → TextView 中携带 fromIndex/removedCount/addedCount/beforeText
  • TYPE_WINDOW_CONTENT_CHANGED → 通过 notifySubtreeAccessibilityStateChanged() 沿 View 树向上传播至 ViewRootImpl
  • TYPE_WINDOW_STATE_CHANGED → ViewRootImpl 在 Activity/Dialog/输入法窗口变化时主动发送

onInitializeAccessibilityEvent() 各控件可重写来填充特有信息(如 CompoundButton 填充 checked 状态)。

三、AccessibilityManager 客户端层

源码路径 :frameworks/base/core/java/android/view/accessibility/AccessibilityManager.java

java 复制代码
public void sendAccessibilityEvent(AccessibilityEvent event) {
    synchronized (mLock) {
        if (!mIsEnabled) {
            event.recycle();
            return;
        }
        // 通过 Handler 异步发送,避免阻塞 UI 线程
        mHandler.sendMessage(mHandler.obtainMessage(
                DO_SET_ACCESSIBILITY_EVENT, event));
    }
}

关键设计:异步发送 。sendAccessibilityEvent() 通常在 UI 线程被调用,如果同步等待 Binder 调用完成会造成 UI 卡顿。通过 Han

相关推荐
传奇开心果编程1 天前
【Flutter踩坑排雷】第7课:巨型 build 函数坑|全部 UI 写在同一个 build,维护难、隐性异常
android·flutter·ios·移动开发·跨平台·dart·声明式ui
方白羽1 天前
Android 双开环境底层剖析与风控检测落地
android·安全·app
weixin_563371471 天前
Android Studio 2024 版 Device Explorer 打开方法
android·ide·android studio
AIsoft_86891 天前
职场音频文件怎么整理?录音APP有哪些用法
android·音视频
booboosui1 天前
第一批个人 Agent 用户正在卸载,问题不在模型,在它住在哪儿
android
洞见前行1 天前
点击图标到内容出现,你的 App 在这几秒里做了什么:Android 冷启动全链路优化实战
android·性能优化·android studio
凯基迪科技1 天前
芯片UID绑定修改 加密与逆向修改思路分析
android
Liben1 天前
Weex开发踩坑记录
android·前端·ios
救救孩子把1 天前
结构化输出为何“格式正确、答案错误”?JSON Schema 的能力边界
android·java·json·agent·agent服务
张小姐的猫1 天前
【MySQL】事务
android·mysql·adb