ViewRootImpl 传递整个绘制过程

本文深入探讨了ViewRootImpl中的performTraversals()方法,重点介绍了measure、layout和draw三个关键步骤及其背后的原理。通过理解这些核心操作,开发者能够更好地掌握Android UI渲染流程。

在 ViewRootImpl 中的performTraversals()

开始准备对 window 里面的孩子,开始进行measureHierarchy(),invalidate(),等操作。

正常步骤为:
1。measure
2。layout
3。draw

在draw的过程中会有维护一个displaylist的 一个东西,并通过flag去判断是否需要重绘

<think>我们正在讨论ViewRootImpl如何将输入事件分发到View树。用户之前的问题已经包含了事件传递的基本流程,现在需要更详细的具体过程。根据引用[1][2][3],ViewRootImpl的事件分发过程可以分为几个关键步骤。 步骤分解: 1. 事件接收:InputEventReceiver接收事件,并放入队列。 2. 事件处理:ViewRootImpl从队列中取出事件,经过一系列处理阶段(InputStage)。 3. 分发到DecorView:在ViewPostImeInputStage阶段,事件被分发给DecorView(即根ViewGroup)。 4. DecorView将事件传递给Activity(如果是触摸事件,则先检查窗口回调)或直接分发给子View。 具体过程如下: 1. **事件接收阶段**: - 当输入事件(如触摸、按键)发生时,底层通过InputDispatcher将事件发送到应用进程。 - 在应用进程,ViewRootImpl的内部类WindowInputEventReceiver的onInputEvent方法被调用,事件被封装为QueuedInputEvent对象并加入队列。 2. **事件处理阶段**: - ViewRootImpl使用一个InputStage链来处理事件。这个链包括: - NativePreImeInputStage:处理本地预处理事件(如系统按键) - ViewPreImeInputStage:视图预处理事件 - ImeInputStage:处理输入法事件 - ViewPostImeInputStage:视图后处理事件(我们关心的阶段) - 在ViewPostImeInputStage中,事件会根据类型(按键、触摸等)被分发给DecorView。 3. **事件分发到DecorView**: - 对于按键事件,调用`mView.dispatchKeyEvent(event)`,其中mView就是DecorView。 - 对于触摸事件,调用`mView.dispatchPointerEvent(event)`,该方法内部会调用`dispatchTouchEvent`。 4. **DecorView的处理**: - DecorView是FrameLayout的子类,它首先将事件传递给Activity(如果有回调)。例如,对于触摸事件: ```java public boolean dispatchTouchEvent(MotionEvent ev) { final Window.Callback cb = mWindow.getCallback(); if (cb != null && !mWindow.isDestroyed() && mFeatureId < 0) { return cb.dispatchTouchEvent(ev); // 这里就是Activity的dispatchTouchEvent } return super.dispatchTouchEvent(ev); } ``` - 如果Activity没有消费事件,则调用`super.dispatchTouchEvent(ev)`,即ViewGroup的dispatchTouchEvent,开始View树的分发。 5. **事件的回溯**: - 事件在View树中按照自上而下(父View到子View)传递,如果没有任何View消费,则最终会回到Activity的onTouchEvent。 注意:引用[2]中提到,DecorView及其父类没有重写dispatchPointerEvent方法,所以调用的是View.dispatchPointerEvent,该方法根据事件类型调用dispatchTouchEvent或dispatchGenericMotionEvent。 整个流程中,ViewRootImpl起到了桥梁作用,将系统输入事件传递到应用内的View树。 下面我们用代码和流程图来详细说明。 </think>### ViewRootImpl输入事件分发的具体过程 #### 一、事件接收阶段 1. **系统输入接收** - InputDispatcher通过共享内存通道发送事件到应用进程 - `WindowInputEventReceiver.onInputEvent()`接收原始事件: ```java final class WindowInputEventReceiver extends InputEventReceiver { @Override public void onInputEvent(InputEvent event) { enqueueInputEvent(event, this, 0, true); // 事件入队处理[^1] } } ``` - 事件被封装为`QueuedInputEvent`对象,加入同步队列 2. **事件同步处理** - 通过`Choreographer`实现VSYNC信号同步 - 主线程设置同步屏障优先处理输入事件 - 关键调用链: `deliverInputEvent()` → `deliverInputEventPostIme()` → `processKeyEvent()/processPointerEvent()` #### 二、分发到DecorView阶段 ```mermaid graph LR A[ViewPostImeInputStage] --> B{事件类型判断} B -->|按键事件| C[调用mView.dispatchKeyEvent] B -->|触摸事件| D[调用mView.dispatchPointerEvent] C --> E[DecorView] D --> E ``` 1. **核心分发逻辑** - 在`ViewPostImeInputStage.processXxxEvent()`中执行: ```java // 按键事件处理 if (mView.dispatchKeyEvent(event)) { return FINISH_HANDLED; // 事件已消费[^1] } ``` - 触摸事件通过`dispatchPointerEvent()`中转: ```java public final boolean dispatchPointerEvent(MotionEvent event) { if (event.isTouchEvent()) { return dispatchTouchEvent(event); // 最终调用DecorView.dispatchTouchEvent[^2] } } ``` 2. **DecorView特殊处理** - **优先传递Activity**: ```java public boolean dispatchTouchEvent(MotionEvent ev) { Window.Callback cb = mWindow.getCallback(); if (cb != null) { return cb.dispatchTouchEvent(ev); // 先传递给Activity[^2] } return super.dispatchTouchEvent(ev); } ``` - **系统区域过滤**:检查状态栏/导航栏触点 - **焦点窗口验证**:丢弃非活动窗口的事件 #### 三、View树传递阶段 1. **ViewGroup分发机制** ```java public boolean dispatchTouchEvent(MotionEvent ev) { // 1. 检查拦截 if (onInterceptTouchEvent(ev)) { return onTouchEvent(ev); // 自行处理 } // 2. 遍历子View(逆序绘制顺序) for (int i = childrenCount - 1; i >= 0; i--) { if (child.dispatchTouchEvent(ev)) { return true; // 子View已消费 } } // 3. 默认处理 return onTouchEvent(ev); } ``` 2. **关键流程特性** - **事件序列跟踪**:通过`MotionEvent.getDownTime()`关联ACTION_DOWN到ACTION_UP - **拦截状态保持**:ViewGroup维护`mFirstTouchTarget`链表记录事件接收者 - **中断处理**:当父View中途拦截时,向子View发送ACTION_CANCEL - **消费优先级**: `OnTouchListener` > `onTouchEvent()` > `OnClickListener` > `OnLongClickListener` #### 四、性能优化设计 1. **事件批处理** - 合并连续ACTION_MOVE事件减少分发次数 - 使用`MotionEvent.getHistoricalX()`读取采样点数据 2. **线程安全机制** - 通过`Looper`消息队列保证主线程执行 - 同步屏障防止事件处理被阻塞: ```java mHandler.getLooper().postSyncBarrier(); // 设置同步屏障[^1] ``` 3. **异常防护** ```java try { return decorView.dispatchTouchEvent(event); } catch (Exception e) { Log.e(TAG, "Event dispatch crashed", e); WindowManagerGlobal.getInstance().closeAll(e); // 安全恢复[^3] } ``` > 整个分发过程满足60fps下事件延迟<16ms的要求。当事件未被消费时,将沿View树原路径回溯直至被Activity处理或丢弃[^1][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值