Skip to content

ViewRootImpl

ZhangPan edited this page Jul 23, 2025 · 9 revisions

ViewRootImpl概述

  1. WindowManager在添加窗口的时候会通过WindowManagerGlobal代理的addView方法来添加View
  2. 在这个addView方法中会实例化ViewRootImpl,并且通过ViewRootImpl.setView将Window的LayoutParams以及DecoreView传递给ViewRootImpl.
  3. WindowManagerGlobal的addView、removeView、updateView都是通过ViewRootImpl来执行的,调用流程为WindowManagerImpl -> WindowManagerGlobal -> ViewRootImpl
  4. ViewRootImpl的setView方法中会通过WindowSession的addToDisplay方法完成Window的添加
  5. WindowSession是一个Binder对象,实现类是Session,也就是说addToDisplay其实是一次IPC过程,调用了远程Session中的addToDisplay方法
  6. Session中的addToDisplay中又调用WindowManagerService的addWindow方法,即Window的添加请求最终是通过WindowManagerService来添加的。
  7. 在Activity的setContentView被调用的时候窗口还没有被添加到WindowManager中,只有在调用了Activity的handleResumeActivity方法才会将DecorView添加到WindowManager中。
  8. ViewRootImpl与Choreograhper配合负责执行View的绘制流程
  9. ImputManagerService->ViewRootimpl配合Choreograhper处理触摸事件的传递

ViewRootImpl 核心功能有以下几点:

  • 连接 View 与 WindowManager: 作为 DecorView 的管理者,负责将视图层级树与 WindowManager 关联,通过 setView() 方法将 DecorView 添加到 WMS;
  • 视图绘制管理
    • 基于 Choreographer 实现 VSync 同步,优化绘制性能
    • 触发测量(Measure)、布局(Layout)、绘制(Draw)流程,通过 performTraversals() 方法协调三大过程视图绘制管理​ 负责 View 的刷新及 View 绘制流程的调用;
  • 事件分发​: 接收系统输入事件(如触摸、按键),通过 dispatchInputEvent() 分发给视图树处理
  • 图形表面管理​: 维护 Surface 对象,通过 SurfaceControl 与 SurfaceFlinger 交互,完成绘制内容的合成与显示
  • 窗口生命周期管理​: 处理窗口的创建、更新、销毁,与 WMS 交互管理窗口属性(如位置、大小、焦点)

ViewRootImpl是一个Android视图层次结构的顶部,是View和WindowManager的桥梁。ViewRootImpl与Choreographer协同完成View的绘制,也负责接收底层的触摸事件和对触摸事件的中转分发。

一、ViewRootImpl与窗口的添加

在WMS中提到WindowManager在添加窗口的时候会调用WindowManagerGlobal代理的addView方法来添加View。

// WindowManagerGlobalpublicvoidaddView(Viewview, ViewGroup.LayoutParamsparams,
Displaydisplay, WindowparentWindow) {
...
ViewRootImplroot;
ViewpanelParentView = null;
...
// 实例化ViewRootImpl root = newViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
//将View添加到ViewRootImpl,开始绘制viewroot.setView(view, wparams, panelParentView);
...
}

WindowManagerGlobal的addView、removeView、UpdateView都是通过ViewRootImpl来执行的。

调用的顺序为 WindowManagerImpl -> WindowManagerGlobal -> ViewRootImpl

而ViewRootImpl的setView如下:

// ViewRootImpl publicvoidsetView(Viewview, WindowManager.LayoutParamsattrs, ViewpanelParentView) {
...
// 添加到Window前先调用requestLayout进行布局,确定收到任何系统事件后重新布局。 // requestLayout方法会完成View的绘制流程 requestLayout();
...
try {
...
// 通过WindowSession完成Window的添加res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
} }

mWindowSession类型是IWindowSession,它是一个Binder对象,真正的实现类是Session,也就是说这其实是一次IPC过程,远程调用了Session中的addToDisPlay方法。

@OverridepublicintaddToDisplay(IWindowwindow, intseq, WindowManager.LayoutParamsattrs,
intviewVisibility, intdisplayId, RectoutContentInsets, RectoutStableInsets,
RectoutOutsets, InputChanneloutInputChannel) {
returnmService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outStableInsets, outOutsets, outInputChannel);
}

这里的mService就是WindowManagerService,也就是说Window的添加请求,最终是通过WindowManagerService来添加的。

Activity中的Window与ViewRootImpl

Activity的setContentView被调用时窗口还未被添加到WindowManager中,也就是此时的View不会开启测量绘制流程。当Activity的handleResumeActivity方法被调用时才会将DecorView添加到WindowManager。而在windowManager.addView方法中调用到windowManagerGlobal.addView,开始创建初始化ViewRootImpl。也就是上面添加Window的过程。

二、ViewRootImpl与View的绘制

ViewRootImpl的requestLayout开启View的绘制流程:

@OverridepublicvoidrequestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
// 检查线程是不是主线程,不是主线程则抛出异常checkThread();
mLayoutRequested = true;
// 开启绘制流程scheduleTraversals();
}
}
voidscheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 通过Handler发送同步屏障消息mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 通过Choreographer发送一个Runnable,Choreographer接收到Vsync信号后通过异步消息执行RunnablemChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
...
}
finalclassTraversalRunnableimplementsRunnable {
@Overridepublicvoidrun() {
// 调用doTraversal开启View的绘制doTraversal();
}
}
voiddoTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
// 移除同步屏障,让非异步消息能够执行mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
// 在这里开启View的测量、布局、绘制三大流程performTraversals();
...
}
}
privatevoidperformTraversals() { // 测量 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
// 布局performLayout(lp, desiredWindowWidth, desiredWindowHeight);
// 绘制performDraw();
}
...
} 

三、ViewRootImpl与事件分发

关于触摸事件时如何从驱动到APP的过程可以参考InputManagerService

ViewRootImpl接收到输入事件,

publicvoiddispatchInputEvent(InputEventevent, InputEventReceiverreceiver) {
// InputEvent是接收到的输入事件,可能是KeyEvent,也可能是MotionEvent// InputEventReceiver用来接收输入事件SomeArgsargs = SomeArgs.obtain();
args.arg1 = event;
args.arg2 = receiver;
// MSG_DISPATCH_INPUT_EVENTMessagemsg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
msg.setAsynchronous(true);
// 通过Handler将消息发送到UI线程mHandler.sendMessage(msg);
}

mHandler是ViewRootImpl的内部类ViewRootHandler,在接收到上述消息后对消息进行处理

finalclassViewRootHandlerextendsHandler {
...
@OverridepublicvoidhandleMessage(Messagemsg) {
switch (msg.what) {
...
caseMSG_DISPATCH_INPUT_EVENT: {
SomeArgsargs = (SomeArgs)msg.obj;
InputEventevent = (InputEvent)args.arg1;
InputEventReceiverreceiver = (InputEventReceiver)args.arg2;
// 在UI线程中调用enqueueInputEventenqueueInputEvent(event, receiver, 0, true);
args.recycle();
} break;
...
}
}
}
voidenqueueInputEvent(InputEventevent,
InputEventReceiverreceiver, intflags, booleanprocessImmediately) {
adjustInputEventForCompatibility(event);
//将当前输入事件加入队列中排列等候执行QueuedInputEventq = obtainQueuedInputEvent(event, receiver, flags);
//输入事件添加进队列后,加入输入事件的默认尾部QueuedInputEventlast = mPendingInputEventTail;
if (last == null) {
mPendingInputEventHead = q;
mPendingInputEventTail = q;
} else {
last.mNext = q;
mPendingInputEventTail = q;
}
//队列计数mPendingInputEventCount += 1;
...
//processImmediately则是判断是同步还是异步,前面我们在handler中调用的,因为是在UI线程,肯定是同步的,所以传递了参数是true,如果是异步,则调用到scheduleProcessInputEvents()if (processImmediately) {
// 循环获取队列中的输入事件doProcessInputEvents();
} else {
// 最终通过Handler post出来,还是调用doProcessInputEvents方法scheduleProcessInputEvents();
}
}

上述代码是将消息封装成QueuedInputEvent,并加入链表的操作。QueuedInputEvent是一个链表结构,代码如下:

privatestaticfinalclassQueuedInputEvent {
...
publicQueuedInputEventmNext;
publicInputEventmEvent;
publicInputEventReceivermReceiver;
...
}

doProcessInputEvents代码如下:

voiddoProcessInputEvents() {
//循环取出队列中的输入事件while (mPendingInputEventHead != null) {
QueuedInputEventq = mPendingInputEventHead;
mPendingInputEventHead = q.mNext;
...
mPendingInputEventCount -= 1;
...
//分发处理deliverInputEvent(q);
}
//处理完所有输入事件,清楚标志if (mProcessInputEventsScheduled) {
mProcessInputEventsScheduled = false;
mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
}
}

通过deliverInputEvent进行分发:

privatevoiddeliverInputEvent(QueuedInputEventq) {
//校验输入事件if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
}
InputStagestage;
if (q.shouldSendToSynthesizer()) {
stage = mSyntheticInputStage;
} else {
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
}
if (stage != null) {
stage.deliver(q);
} else {
finishInputEvent(q);
}
}

这里InputStage则是一个实现处理输入事件责任的阶段,提供一系列处理输入事件的方法。每种InputStage可以处理一定的事件类型,比如AsyncInputStage、ViewPreImeInputStage、ViewPostImeInputStage等。当一个InputEvent到来时,ViewRootImpl会寻找合适它的InputStage来处理。

InputStage会先调用deliver开始处理,最终调用onProcess方法。对于View的点击事件可以用ViewPostImeInputStage来处理,它的onProcess方法如下:

@OverrideprotectedintonProcess(QueuedInputEventq) {
if (q.mEventinstanceofKeyEvent) {
returnprocessKeyEvent(q);
} else {
// If delivering a new non-key event, make sure the window is// now allowed to start updating.handleDispatchWindowAnimationStopped();
finalintsource = q.mEvent.getSource();
if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
// 判断是触摸事件调用该方法returnprocessPointerEvent(q);
} elseif ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
returnprocessTrackballEvent(q);
} else {
returnprocessGenericMotionEvent(q);
}
}
}
privateintprocessPointerEvent(QueuedInputEventq) {
// 触摸事件finalMotionEventevent = (MotionEvent)q.mEvent;
mAttachInfo.mUnbufferedDispatchRequested = false;
// 调用DocerView的dispatchPointerEvent,将分发事件交给Viewbooleanhandled = mView.dispatchPointerEvent(event);
...
returnhandled ? FINISH_HANDLED : FORWARD;
}

View的dispatchPointerEvent代码如下:

publicfinalbooleandispatchPointerEvent(MotionEventevent) {
if (event.isTouchEvent()) {
// 如果是TouchEvent,则开启事件分发returndispatchTouchEvent(event);
} else {
returndispatchGenericMotionEvent(event);
}
}

https://www.jianshu.com/p/9da7bfe18374

https://www.jianshu.com/p/9e6c54739217

公众号:玩转安卓Dev

Java基础

面向对象与Java基础知识

Java集合框架

JVM

多线程与并发

设计模式

Kotlin

Android

项目相关问题

Android基础知识

Android消息机制

Android Binder

View事件分发机制

Android屏幕刷新机制

View的绘制流程

Activity启动

Framework

性能优化

Jetpack&系统View

第三方框架实现原理

计算机网络

算法

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
ViewRootImpl · zhpanvip/AndroidNote Wiki · GitHub
Skip to content

ViewRootImpl

ZhangPan edited this page Jul 23, 2025 · 9 revisions

ViewRootImpl概述

  1. WindowManager在添加窗口的时候会通过WindowManagerGlobal代理的addView方法来添加View
  2. 在这个addView方法中会实例化ViewRootImpl,并且通过ViewRootImpl.setView将Window的LayoutParams以及DecoreView传递给ViewRootImpl.
  3. WindowManagerGlobal的addView、removeView、updateView都是通过ViewRootImpl来执行的,调用流程为WindowManagerImpl -> WindowManagerGlobal -> ViewRootImpl
  4. ViewRootImpl的setView方法中会通过WindowSession的addToDisplay方法完成Window的添加
  5. WindowSession是一个Binder对象,实现类是Session,也就是说addToDisplay其实是一次IPC过程,调用了远程Session中的addToDisplay方法
  6. Session中的addToDisplay中又调用WindowManagerService的addWindow方法,即Window的添加请求最终是通过WindowManagerService来添加的。
  7. 在Activity的setContentView被调用的时候窗口还没有被添加到WindowManager中,只有在调用了Activity的handleResumeActivity方法才会将DecorView添加到WindowManager中。
  8. ViewRootImpl与Choreograhper配合负责执行View的绘制流程
  9. ImputManagerService->ViewRootimpl配合Choreograhper处理触摸事件的传递

ViewRootImpl 核心功能有以下几点:

  • 连接 View 与 WindowManager: 作为 DecorView 的管理者,负责将视图层级树与 WindowManager 关联,通过 setView() 方法将 DecorView 添加到 WMS;
  • 视图绘制管理
    • 基于 Choreographer 实现 VSync 同步,优化绘制性能
    • 触发测量(Measure)、布局(Layout)、绘制(Draw)流程,通过 performTraversals() 方法协调三大过程视图绘制管理​ 负责 View 的刷新及 View 绘制流程的调用;
  • 事件分发​: 接收系统输入事件(如触摸、按键),通过 dispatchInputEvent() 分发给视图树处理
  • 图形表面管理​: 维护 Surface 对象,通过 SurfaceControl 与 SurfaceFlinger 交互,完成绘制内容的合成与显示
  • 窗口生命周期管理​: 处理窗口的创建、更新、销毁,与 WMS 交互管理窗口属性(如位置、大小、焦点)

ViewRootImpl是一个Android视图层次结构的顶部,是View和WindowManager的桥梁。ViewRootImpl与Choreographer协同完成View的绘制,也负责接收底层的触摸事件和对触摸事件的中转分发。

一、ViewRootImpl与窗口的添加

在WMS中提到WindowManager在添加窗口的时候会调用WindowManagerGlobal代理的addView方法来添加View。

// WindowManagerGlobalpublicvoidaddView(Viewview, ViewGroup.LayoutParamsparams,
Displaydisplay, WindowparentWindow) {
...
ViewRootImplroot;
ViewpanelParentView = null;
...
// 实例化ViewRootImpl root = newViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
//将View添加到ViewRootImpl,开始绘制viewroot.setView(view, wparams, panelParentView);
...
}

WindowManagerGlobal的addView、removeView、UpdateView都是通过ViewRootImpl来执行的。

调用的顺序为 WindowManagerImpl -> WindowManagerGlobal -> ViewRootImpl

而ViewRootImpl的setView如下:

// ViewRootImpl publicvoidsetView(Viewview, WindowManager.LayoutParamsattrs, ViewpanelParentView) {
...
// 添加到Window前先调用requestLayout进行布局,确定收到任何系统事件后重新布局。 // requestLayout方法会完成View的绘制流程 requestLayout();
...
try {
...
// 通过WindowSession完成Window的添加res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
} }

mWindowSession类型是IWindowSession,它是一个Binder对象,真正的实现类是Session,也就是说这其实是一次IPC过程,远程调用了Session中的addToDisPlay方法。

@OverridepublicintaddToDisplay(IWindowwindow, intseq, WindowManager.LayoutParamsattrs,
intviewVisibility, intdisplayId, RectoutContentInsets, RectoutStableInsets,
RectoutOutsets, InputChanneloutInputChannel) {
returnmService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outStableInsets, outOutsets, outInputChannel);
}

这里的mService就是WindowManagerService,也就是说Window的添加请求,最终是通过WindowManagerService来添加的。

Activity中的Window与ViewRootImpl

Activity的setContentView被调用时窗口还未被添加到WindowManager中,也就是此时的View不会开启测量绘制流程。当Activity的handleResumeActivity方法被调用时才会将DecorView添加到WindowManager。而在windowManager.addView方法中调用到windowManagerGlobal.addView,开始创建初始化ViewRootImpl。也就是上面添加Window的过程。

二、ViewRootImpl与View的绘制

ViewRootImpl的requestLayout开启View的绘制流程:

@OverridepublicvoidrequestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
// 检查线程是不是主线程,不是主线程则抛出异常checkThread();
mLayoutRequested = true;
// 开启绘制流程scheduleTraversals();
}
}
voidscheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 通过Handler发送同步屏障消息mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 通过Choreographer发送一个Runnable,Choreographer接收到Vsync信号后通过异步消息执行RunnablemChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
...
}
finalclassTraversalRunnableimplementsRunnable {
@Overridepublicvoidrun() {
// 调用doTraversal开启View的绘制doTraversal();
}
}
voiddoTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
// 移除同步屏障,让非异步消息能够执行mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
// 在这里开启View的测量、布局、绘制三大流程performTraversals();
...
}
}
privatevoidperformTraversals() { // 测量 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
// 布局performLayout(lp, desiredWindowWidth, desiredWindowHeight);
// 绘制performDraw();
}
...
} 

三、ViewRootImpl与事件分发

关于触摸事件时如何从驱动到APP的过程可以参考InputManagerService

ViewRootImpl接收到输入事件,

publicvoiddispatchInputEvent(InputEventevent, InputEventReceiverreceiver) {
// InputEvent是接收到的输入事件,可能是KeyEvent,也可能是MotionEvent// InputEventReceiver用来接收输入事件SomeArgsargs = SomeArgs.obtain();
args.arg1 = event;
args.arg2 = receiver;
// MSG_DISPATCH_INPUT_EVENTMessagemsg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
msg.setAsynchronous(true);
// 通过Handler将消息发送到UI线程mHandler.sendMessage(msg);
}

mHandler是ViewRootImpl的内部类ViewRootHandler,在接收到上述消息后对消息进行处理

finalclassViewRootHandlerextendsHandler {
...
@OverridepublicvoidhandleMessage(Messagemsg) {
switch (msg.what) {
...
caseMSG_DISPATCH_INPUT_EVENT: {
SomeArgsargs = (SomeArgs)msg.obj;
InputEventevent = (InputEvent)args.arg1;
InputEventReceiverreceiver = (InputEventReceiver)args.arg2;
// 在UI线程中调用enqueueInputEventenqueueInputEvent(event, receiver, 0, true);
args.recycle();
} break;
...
}
}
}
voidenqueueInputEvent(InputEventevent,
InputEventReceiverreceiver, intflags, booleanprocessImmediately) {
adjustInputEventForCompatibility(event);
//将当前输入事件加入队列中排列等候执行QueuedInputEventq = obtainQueuedInputEvent(event, receiver, flags);
//输入事件添加进队列后,加入输入事件的默认尾部QueuedInputEventlast = mPendingInputEventTail;
if (last == null) {
mPendingInputEventHead = q;
mPendingInputEventTail = q;
} else {
last.mNext = q;
mPendingInputEventTail = q;
}
//队列计数mPendingInputEventCount += 1;
...
//processImmediately则是判断是同步还是异步,前面我们在handler中调用的,因为是在UI线程,肯定是同步的,所以传递了参数是true,如果是异步,则调用到scheduleProcessInputEvents()if (processImmediately) {
// 循环获取队列中的输入事件doProcessInputEvents();
} else {
// 最终通过Handler post出来,还是调用doProcessInputEvents方法scheduleProcessInputEvents();
}
}

上述代码是将消息封装成QueuedInputEvent,并加入链表的操作。QueuedInputEvent是一个链表结构,代码如下:

privatestaticfinalclassQueuedInputEvent {
...
publicQueuedInputEventmNext;
publicInputEventmEvent;
publicInputEventReceivermReceiver;
...
}

doProcessInputEvents代码如下:

voiddoProcessInputEvents() {
//循环取出队列中的输入事件while (mPendingInputEventHead != null) {
QueuedInputEventq = mPendingInputEventHead;
mPendingInputEventHead = q.mNext;
...
mPendingInputEventCount -= 1;
...
//分发处理deliverInputEvent(q);
}
//处理完所有输入事件,清楚标志if (mProcessInputEventsScheduled) {
mProcessInputEventsScheduled = false;
mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
}
}

通过deliverInputEvent进行分发:

privatevoiddeliverInputEvent(QueuedInputEventq) {
//校验输入事件if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
}
InputStagestage;
if (q.shouldSendToSynthesizer()) {
stage = mSyntheticInputStage;
} else {
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
}
if (stage != null) {
stage.deliver(q);
} else {
finishInputEvent(q);
}
}

这里InputStage则是一个实现处理输入事件责任的阶段,提供一系列处理输入事件的方法。每种InputStage可以处理一定的事件类型,比如AsyncInputStage、ViewPreImeInputStage、ViewPostImeInputStage等。当一个InputEvent到来时,ViewRootImpl会寻找合适它的InputStage来处理。

InputStage会先调用deliver开始处理,最终调用onProcess方法。对于View的点击事件可以用ViewPostImeInputStage来处理,它的onProcess方法如下:

@OverrideprotectedintonProcess(QueuedInputEventq) {
if (q.mEventinstanceofKeyEvent) {
returnprocessKeyEvent(q);
} else {
// If delivering a new non-key event, make sure the window is// now allowed to start updating.handleDispatchWindowAnimationStopped();
finalintsource = q.mEvent.getSource();
if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
// 判断是触摸事件调用该方法returnprocessPointerEvent(q);
} elseif ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
returnprocessTrackballEvent(q);
} else {
returnprocessGenericMotionEvent(q);
}
}
}
privateintprocessPointerEvent(QueuedInputEventq) {
// 触摸事件finalMotionEventevent = (MotionEvent)q.mEvent;
mAttachInfo.mUnbufferedDispatchRequested = false;
// 调用DocerView的dispatchPointerEvent,将分发事件交给Viewbooleanhandled = mView.dispatchPointerEvent(event);
...
returnhandled ? FINISH_HANDLED : FORWARD;
}

View的dispatchPointerEvent代码如下:

publicfinalbooleandispatchPointerEvent(MotionEventevent) {
if (event.isTouchEvent()) {
// 如果是TouchEvent,则开启事件分发returndispatchTouchEvent(event);
} else {
returndispatchGenericMotionEvent(event);
}
}

https://www.jianshu.com/p/9da7bfe18374

https://www.jianshu.com/p/9e6c54739217

公众号:玩转安卓Dev

Java基础

面向对象与Java基础知识

Java集合框架

JVM

多线程与并发

设计模式

Kotlin

Android

项目相关问题

Android基础知识

Android消息机制

Android Binder

View事件分发机制

Android屏幕刷新机制

View的绘制流程

Activity启动

Framework

性能优化

Jetpack&系统View

第三方框架实现原理

计算机网络

算法

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' ViewRootImpl · zhpanvip/AndroidNote Wiki · GitHub
Skip to content

ViewRootImpl

ZhangPan edited this page Jul 23, 2025 · 9 revisions

ViewRootImpl概述

  1. WindowManager在添加窗口的时候会通过WindowManagerGlobal代理的addView方法来添加View
  2. 在这个addView方法中会实例化ViewRootImpl,并且通过ViewRootImpl.setView将Window的LayoutParams以及DecoreView传递给ViewRootImpl.
  3. WindowManagerGlobal的addView、removeView、updateView都是通过ViewRootImpl来执行的,调用流程为WindowManagerImpl -> WindowManagerGlobal -> ViewRootImpl
  4. ViewRootImpl的setView方法中会通过WindowSession的addToDisplay方法完成Window的添加
  5. WindowSession是一个Binder对象,实现类是Session,也就是说addToDisplay其实是一次IPC过程,调用了远程Session中的addToDisplay方法
  6. Session中的addToDisplay中又调用WindowManagerService的addWindow方法,即Window的添加请求最终是通过WindowManagerService来添加的。
  7. 在Activity的setContentView被调用的时候窗口还没有被添加到WindowManager中,只有在调用了Activity的handleResumeActivity方法才会将DecorView添加到WindowManager中。
  8. ViewRootImpl与Choreograhper配合负责执行View的绘制流程
  9. ImputManagerService->ViewRootimpl配合Choreograhper处理触摸事件的传递

ViewRootImpl 核心功能有以下几点:

  • 连接 View 与 WindowManager: 作为 DecorView 的管理者,负责将视图层级树与 WindowManager 关联,通过 setView() 方法将 DecorView 添加到 WMS;
  • 视图绘制管理
    • 基于 Choreographer 实现 VSync 同步,优化绘制性能
    • 触发测量(Measure)、布局(Layout)、绘制(Draw)流程,通过 performTraversals() 方法协调三大过程视图绘制管理​ 负责 View 的刷新及 View 绘制流程的调用;
  • 事件分发​: 接收系统输入事件(如触摸、按键),通过 dispatchInputEvent() 分发给视图树处理
  • 图形表面管理​: 维护 Surface 对象,通过 SurfaceControl 与 SurfaceFlinger 交互,完成绘制内容的合成与显示
  • 窗口生命周期管理​: 处理窗口的创建、更新、销毁,与 WMS 交互管理窗口属性(如位置、大小、焦点)

ViewRootImpl是一个Android视图层次结构的顶部,是View和WindowManager的桥梁。ViewRootImpl与Choreographer协同完成View的绘制,也负责接收底层的触摸事件和对触摸事件的中转分发。

一、ViewRootImpl与窗口的添加

在WMS中提到WindowManager在添加窗口的时候会调用WindowManagerGlobal代理的addView方法来添加View。

// WindowManagerGlobalpublicvoidaddView(Viewview, ViewGroup.LayoutParamsparams,
Displaydisplay, WindowparentWindow) {
...
ViewRootImplroot;
ViewpanelParentView = null;
...
// 实例化ViewRootImpl root = newViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
//将View添加到ViewRootImpl,开始绘制viewroot.setView(view, wparams, panelParentView);
...
}

WindowManagerGlobal的addView、removeView、UpdateView都是通过ViewRootImpl来执行的。

调用的顺序为 WindowManagerImpl -> WindowManagerGlobal -> ViewRootImpl

而ViewRootImpl的setView如下:

// ViewRootImpl publicvoidsetView(Viewview, WindowManager.LayoutParamsattrs, ViewpanelParentView) {
...
// 添加到Window前先调用requestLayout进行布局,确定收到任何系统事件后重新布局。 // requestLayout方法会完成View的绘制流程 requestLayout();
...
try {
...
// 通过WindowSession完成Window的添加res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
} }

mWindowSession类型是IWindowSession,它是一个Binder对象,真正的实现类是Session,也就是说这其实是一次IPC过程,远程调用了Session中的addToDisPlay方法。

@OverridepublicintaddToDisplay(IWindowwindow, intseq, WindowManager.LayoutParamsattrs,
intviewVisibility, intdisplayId, RectoutContentInsets, RectoutStableInsets,
RectoutOutsets, InputChanneloutInputChannel) {
returnmService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outStableInsets, outOutsets, outInputChannel);
}

这里的mService就是WindowManagerService,也就是说Window的添加请求,最终是通过WindowManagerService来添加的。

Activity中的Window与ViewRootImpl

Activity的setContentView被调用时窗口还未被添加到WindowManager中,也就是此时的View不会开启测量绘制流程。当Activity的handleResumeActivity方法被调用时才会将DecorView添加到WindowManager。而在windowManager.addView方法中调用到windowManagerGlobal.addView,开始创建初始化ViewRootImpl。也就是上面添加Window的过程。

二、ViewRootImpl与View的绘制

ViewRootImpl的requestLayout开启View的绘制流程:

@OverridepublicvoidrequestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
// 检查线程是不是主线程,不是主线程则抛出异常checkThread();
mLayoutRequested = true;
// 开启绘制流程scheduleTraversals();
}
}
voidscheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 通过Handler发送同步屏障消息mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 通过Choreographer发送一个Runnable,Choreographer接收到Vsync信号后通过异步消息执行RunnablemChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
...
}
finalclassTraversalRunnableimplementsRunnable {
@Overridepublicvoidrun() {
// 调用doTraversal开启View的绘制doTraversal();
}
}
voiddoTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
// 移除同步屏障,让非异步消息能够执行mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
// 在这里开启View的测量、布局、绘制三大流程performTraversals();
...
}
}
privatevoidperformTraversals() { // 测量 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
// 布局performLayout(lp, desiredWindowWidth, desiredWindowHeight);
// 绘制performDraw();
}
...
} 

三、ViewRootImpl与事件分发

关于触摸事件时如何从驱动到APP的过程可以参考InputManagerService

ViewRootImpl接收到输入事件,

publicvoiddispatchInputEvent(InputEventevent, InputEventReceiverreceiver) {
// InputEvent是接收到的输入事件,可能是KeyEvent,也可能是MotionEvent// InputEventReceiver用来接收输入事件SomeArgsargs = SomeArgs.obtain();
args.arg1 = event;
args.arg2 = receiver;
// MSG_DISPATCH_INPUT_EVENTMessagemsg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
msg.setAsynchronous(true);
// 通过Handler将消息发送到UI线程mHandler.sendMessage(msg);
}

mHandler是ViewRootImpl的内部类ViewRootHandler,在接收到上述消息后对消息进行处理

finalclassViewRootHandlerextendsHandler {
...
@OverridepublicvoidhandleMessage(Messagemsg) {
switch (msg.what) {
...
caseMSG_DISPATCH_INPUT_EVENT: {
SomeArgsargs = (SomeArgs)msg.obj;
InputEventevent = (InputEvent)args.arg1;
InputEventReceiverreceiver = (InputEventReceiver)args.arg2;
// 在UI线程中调用enqueueInputEventenqueueInputEvent(event, receiver, 0, true);
args.recycle();
} break;
...
}
}
}
voidenqueueInputEvent(InputEventevent,
InputEventReceiverreceiver, intflags, booleanprocessImmediately) {
adjustInputEventForCompatibility(event);
//将当前输入事件加入队列中排列等候执行QueuedInputEventq = obtainQueuedInputEvent(event, receiver, flags);
//输入事件添加进队列后,加入输入事件的默认尾部QueuedInputEventlast = mPendingInputEventTail;
if (last == null) {
mPendingInputEventHead = q;
mPendingInputEventTail = q;
} else {
last.mNext = q;
mPendingInputEventTail = q;
}
//队列计数mPendingInputEventCount += 1;
...
//processImmediately则是判断是同步还是异步,前面我们在handler中调用的,因为是在UI线程,肯定是同步的,所以传递了参数是true,如果是异步,则调用到scheduleProcessInputEvents()if (processImmediately) {
// 循环获取队列中的输入事件doProcessInputEvents();
} else {
// 最终通过Handler post出来,还是调用doProcessInputEvents方法scheduleProcessInputEvents();
}
}

上述代码是将消息封装成QueuedInputEvent,并加入链表的操作。QueuedInputEvent是一个链表结构,代码如下:

privatestaticfinalclassQueuedInputEvent {
...
publicQueuedInputEventmNext;
publicInputEventmEvent;
publicInputEventReceivermReceiver;
...
}

doProcessInputEvents代码如下:

voiddoProcessInputEvents() {
//循环取出队列中的输入事件while (mPendingInputEventHead != null) {
QueuedInputEventq = mPendingInputEventHead;
mPendingInputEventHead = q.mNext;
...
mPendingInputEventCount -= 1;
...
//分发处理deliverInputEvent(q);
}
//处理完所有输入事件,清楚标志if (mProcessInputEventsScheduled) {
mProcessInputEventsScheduled = false;
mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
}
}

通过deliverInputEvent进行分发:

privatevoiddeliverInputEvent(QueuedInputEventq) {
//校验输入事件if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
}
InputStagestage;
if (q.shouldSendToSynthesizer()) {
stage = mSyntheticInputStage;
} else {
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
}
if (stage != null) {
stage.deliver(q);
} else {
finishInputEvent(q);
}
}

这里InputStage则是一个实现处理输入事件责任的阶段,提供一系列处理输入事件的方法。每种InputStage可以处理一定的事件类型,比如AsyncInputStage、ViewPreImeInputStage、ViewPostImeInputStage等。当一个InputEvent到来时,ViewRootImpl会寻找合适它的InputStage来处理。

InputStage会先调用deliver开始处理,最终调用onProcess方法。对于View的点击事件可以用ViewPostImeInputStage来处理,它的onProcess方法如下:

@OverrideprotectedintonProcess(QueuedInputEventq) {
if (q.mEventinstanceofKeyEvent) {
returnprocessKeyEvent(q);
} else {
// If delivering a new non-key event, make sure the window is// now allowed to start updating.handleDispatchWindowAnimationStopped();
finalintsource = q.mEvent.getSource();
if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
// 判断是触摸事件调用该方法returnprocessPointerEvent(q);
} elseif ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
returnprocessTrackballEvent(q);
} else {
returnprocessGenericMotionEvent(q);
}
}
}
privateintprocessPointerEvent(QueuedInputEventq) {
// 触摸事件finalMotionEventevent = (MotionEvent)q.mEvent;
mAttachInfo.mUnbufferedDispatchRequested = false;
// 调用DocerView的dispatchPointerEvent,将分发事件交给Viewbooleanhandled = mView.dispatchPointerEvent(event);
...
returnhandled ? FINISH_HANDLED : FORWARD;
}

View的dispatchPointerEvent代码如下:

publicfinalbooleandispatchPointerEvent(MotionEventevent) {
if (event.isTouchEvent()) {
// 如果是TouchEvent,则开启事件分发returndispatchTouchEvent(event);
} else {
returndispatchGenericMotionEvent(event);
}
}

https://www.jianshu.com/p/9da7bfe18374

https://www.jianshu.com/p/9e6c54739217

公众号:玩转安卓Dev

Java基础

面向对象与Java基础知识

Java集合框架

JVM

多线程与并发

设计模式

Kotlin

Android

项目相关问题

Android基础知识

Android消息机制

Android Binder

View事件分发机制

Android屏幕刷新机制

View的绘制流程

Activity启动

Framework

性能优化

Jetpack&系统View

第三方框架实现原理

计算机网络

算法

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' ViewRootImpl · zhpanvip/AndroidNote Wiki · GitHub
Skip to content

ViewRootImpl

ZhangPan edited this page Jul 23, 2025 · 9 revisions

ViewRootImpl概述

  1. WindowManager在添加窗口的时候会通过WindowManagerGlobal代理的addView方法来添加View
  2. 在这个addView方法中会实例化ViewRootImpl,并且通过ViewRootImpl.setView将Window的LayoutParams以及DecoreView传递给ViewRootImpl.
  3. WindowManagerGlobal的addView、removeView、updateView都是通过ViewRootImpl来执行的,调用流程为WindowManagerImpl -> WindowManagerGlobal -> ViewRootImpl
  4. ViewRootImpl的setView方法中会通过WindowSession的addToDisplay方法完成Window的添加
  5. WindowSession是一个Binder对象,实现类是Session,也就是说addToDisplay其实是一次IPC过程,调用了远程Session中的addToDisplay方法
  6. Session中的addToDisplay中又调用WindowManagerService的addWindow方法,即Window的添加请求最终是通过WindowManagerService来添加的。
  7. 在Activity的setContentView被调用的时候窗口还没有被添加到WindowManager中,只有在调用了Activity的handleResumeActivity方法才会将DecorView添加到WindowManager中。
  8. ViewRootImpl与Choreograhper配合负责执行View的绘制流程
  9. ImputManagerService->ViewRootimpl配合Choreograhper处理触摸事件的传递

ViewRootImpl 核心功能有以下几点:

  • 连接 View 与 WindowManager: 作为 DecorView 的管理者,负责将视图层级树与 WindowManager 关联,通过 setView() 方法将 DecorView 添加到 WMS;
  • 视图绘制管理
    • 基于 Choreographer 实现 VSync 同步,优化绘制性能
    • 触发测量(Measure)、布局(Layout)、绘制(Draw)流程,通过 performTraversals() 方法协调三大过程视图绘制管理​ 负责 View 的刷新及 View 绘制流程的调用;
  • 事件分发​: 接收系统输入事件(如触摸、按键),通过 dispatchInputEvent() 分发给视图树处理
  • 图形表面管理​: 维护 Surface 对象,通过 SurfaceControl 与 SurfaceFlinger 交互,完成绘制内容的合成与显示
  • 窗口生命周期管理​: 处理窗口的创建、更新、销毁,与 WMS 交互管理窗口属性(如位置、大小、焦点)

ViewRootImpl是一个Android视图层次结构的顶部,是View和WindowManager的桥梁。ViewRootImpl与Choreographer协同完成View的绘制,也负责接收底层的触摸事件和对触摸事件的中转分发。

一、ViewRootImpl与窗口的添加

在WMS中提到WindowManager在添加窗口的时候会调用WindowManagerGlobal代理的addView方法来添加View。

// WindowManagerGlobalpublicvoidaddView(Viewview, ViewGroup.LayoutParamsparams,
Displaydisplay, WindowparentWindow) {
...
ViewRootImplroot;
ViewpanelParentView = null;
...
// 实例化ViewRootImpl root = newViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
//将View添加到ViewRootImpl,开始绘制viewroot.setView(view, wparams, panelParentView);
...
}

WindowManagerGlobal的addView、removeView、UpdateView都是通过ViewRootImpl来执行的。

调用的顺序为 WindowManagerImpl -> WindowManagerGlobal -> ViewRootImpl

而ViewRootImpl的setView如下:

// ViewRootImpl publicvoidsetView(Viewview, WindowManager.LayoutParamsattrs, ViewpanelParentView) {
...
// 添加到Window前先调用requestLayout进行布局,确定收到任何系统事件后重新布局。 // requestLayout方法会完成View的绘制流程 requestLayout();
...
try {
...
// 通过WindowSession完成Window的添加res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
} }

mWindowSession类型是IWindowSession,它是一个Binder对象,真正的实现类是Session,也就是说这其实是一次IPC过程,远程调用了Session中的addToDisPlay方法。

@OverridepublicintaddToDisplay(IWindowwindow, intseq, WindowManager.LayoutParamsattrs,
intviewVisibility, intdisplayId, RectoutContentInsets, RectoutStableInsets,
RectoutOutsets, InputChanneloutInputChannel) {
returnmService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outStableInsets, outOutsets, outInputChannel);
}

这里的mService就是WindowManagerService,也就是说Window的添加请求,最终是通过WindowManagerService来添加的。

Activity中的Window与ViewRootImpl

Activity的setContentView被调用时窗口还未被添加到WindowManager中,也就是此时的View不会开启测量绘制流程。当Activity的handleResumeActivity方法被调用时才会将DecorView添加到WindowManager。而在windowManager.addView方法中调用到windowManagerGlobal.addView,开始创建初始化ViewRootImpl。也就是上面添加Window的过程。

二、ViewRootImpl与View的绘制

ViewRootImpl的requestLayout开启View的绘制流程:

@OverridepublicvoidrequestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
// 检查线程是不是主线程,不是主线程则抛出异常checkThread();
mLayoutRequested = true;
// 开启绘制流程scheduleTraversals();
}
}
voidscheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 通过Handler发送同步屏障消息mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 通过Choreographer发送一个Runnable,Choreographer接收到Vsync信号后通过异步消息执行RunnablemChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
...
}
finalclassTraversalRunnableimplementsRunnable {
@Overridepublicvoidrun() {
// 调用doTraversal开启View的绘制doTraversal();
}
}
voiddoTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
// 移除同步屏障,让非异步消息能够执行mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
// 在这里开启View的测量、布局、绘制三大流程performTraversals();
...
}
}
privatevoidperformTraversals() { // 测量 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
// 布局performLayout(lp, desiredWindowWidth, desiredWindowHeight);
// 绘制performDraw();
}
...
} 

三、ViewRootImpl与事件分发

关于触摸事件时如何从驱动到APP的过程可以参考InputManagerService

ViewRootImpl接收到输入事件,

publicvoiddispatchInputEvent(InputEventevent, InputEventReceiverreceiver) {
// InputEvent是接收到的输入事件,可能是KeyEvent,也可能是MotionEvent// InputEventReceiver用来接收输入事件SomeArgsargs = SomeArgs.obtain();
args.arg1 = event;
args.arg2 = receiver;
// MSG_DISPATCH_INPUT_EVENTMessagemsg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
msg.setAsynchronous(true);
// 通过Handler将消息发送到UI线程mHandler.sendMessage(msg);
}

mHandler是ViewRootImpl的内部类ViewRootHandler,在接收到上述消息后对消息进行处理

finalclassViewRootHandlerextendsHandler {
...
@OverridepublicvoidhandleMessage(Messagemsg) {
switch (msg.what) {
...
caseMSG_DISPATCH_INPUT_EVENT: {
SomeArgsargs = (SomeArgs)msg.obj;
InputEventevent = (InputEvent)args.arg1;
InputEventReceiverreceiver = (InputEventReceiver)args.arg2;
// 在UI线程中调用enqueueInputEventenqueueInputEvent(event, receiver, 0, true);
args.recycle();
} break;
...
}
}
}
voidenqueueInputEvent(InputEventevent,
InputEventReceiverreceiver, intflags, booleanprocessImmediately) {
adjustInputEventForCompatibility(event);
//将当前输入事件加入队列中排列等候执行QueuedInputEventq = obtainQueuedInputEvent(event, receiver, flags);
//输入事件添加进队列后,加入输入事件的默认尾部QueuedInputEventlast = mPendingInputEventTail;
if (last == null) {
mPendingInputEventHead = q;
mPendingInputEventTail = q;
} else {
last.mNext = q;
mPendingInputEventTail = q;
}
//队列计数mPendingInputEventCount += 1;
...
//processImmediately则是判断是同步还是异步,前面我们在handler中调用的,因为是在UI线程,肯定是同步的,所以传递了参数是true,如果是异步,则调用到scheduleProcessInputEvents()if (processImmediately) {
// 循环获取队列中的输入事件doProcessInputEvents();
} else {
// 最终通过Handler post出来,还是调用doProcessInputEvents方法scheduleProcessInputEvents();
}
}

上述代码是将消息封装成QueuedInputEvent,并加入链表的操作。QueuedInputEvent是一个链表结构,代码如下:

privatestaticfinalclassQueuedInputEvent {
...
publicQueuedInputEventmNext;
publicInputEventmEvent;
publicInputEventReceivermReceiver;
...
}

doProcessInputEvents代码如下:

voiddoProcessInputEvents() {
//循环取出队列中的输入事件while (mPendingInputEventHead != null) {
QueuedInputEventq = mPendingInputEventHead;
mPendingInputEventHead = q.mNext;
...
mPendingInputEventCount -= 1;
...
//分发处理deliverInputEvent(q);
}
//处理完所有输入事件,清楚标志if (mProcessInputEventsScheduled) {
mProcessInputEventsScheduled = false;
mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
}
}

通过deliverInputEvent进行分发:

privatevoiddeliverInputEvent(QueuedInputEventq) {
//校验输入事件if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
}
InputStagestage;
if (q.shouldSendToSynthesizer()) {
stage = mSyntheticInputStage;
} else {
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
}
if (stage != null) {
stage.deliver(q);
} else {
finishInputEvent(q);
}
}

这里InputStage则是一个实现处理输入事件责任的阶段,提供一系列处理输入事件的方法。每种InputStage可以处理一定的事件类型,比如AsyncInputStage、ViewPreImeInputStage、ViewPostImeInputStage等。当一个InputEvent到来时,ViewRootImpl会寻找合适它的InputStage来处理。

InputStage会先调用deliver开始处理,最终调用onProcess方法。对于View的点击事件可以用ViewPostImeInputStage来处理,它的onProcess方法如下:

@OverrideprotectedintonProcess(QueuedInputEventq) {
if (q.mEventinstanceofKeyEvent) {
returnprocessKeyEvent(q);
} else {
// If delivering a new non-key event, make sure the window is// now allowed to start updating.handleDispatchWindowAnimationStopped();
finalintsource = q.mEvent.getSource();
if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
// 判断是触摸事件调用该方法returnprocessPointerEvent(q);
} elseif ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
returnprocessTrackballEvent(q);
} else {
returnprocessGenericMotionEvent(q);
}
}
}
privateintprocessPointerEvent(QueuedInputEventq) {
// 触摸事件finalMotionEventevent = (MotionEvent)q.mEvent;
mAttachInfo.mUnbufferedDispatchRequested = false;
// 调用DocerView的dispatchPointerEvent,将分发事件交给Viewbooleanhandled = mView.dispatchPointerEvent(event);
...
returnhandled ? FINISH_HANDLED : FORWARD;
}

View的dispatchPointerEvent代码如下:

publicfinalbooleandispatchPointerEvent(MotionEventevent) {
if (event.isTouchEvent()) {
// 如果是TouchEvent,则开启事件分发returndispatchTouchEvent(event);
} else {
returndispatchGenericMotionEvent(event);
}
}

https://www.jianshu.com/p/9da7bfe18374

https://www.jianshu.com/p/9e6c54739217

公众号:玩转安卓Dev

Java基础

面向对象与Java基础知识

Java集合框架

JVM

多线程与并发

设计模式

Kotlin

Android

项目相关问题

Android基础知识

Android消息机制

Android Binder

View事件分发机制

Android屏幕刷新机制

View的绘制流程

Activity启动

Framework

性能优化

Jetpack&系统View

第三方框架实现原理

计算机网络

算法

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' ViewRootImpl · zhpanvip/AndroidNote Wiki · GitHub
Skip to content

ViewRootImpl

ZhangPan edited this page Jul 23, 2025 · 9 revisions

ViewRootImpl概述

  1. WindowManager在添加窗口的时候会通过WindowManagerGlobal代理的addView方法来添加View
  2. 在这个addView方法中会实例化ViewRootImpl,并且通过ViewRootImpl.setView将Window的LayoutParams以及DecoreView传递给ViewRootImpl.
  3. WindowManagerGlobal的addView、removeView、updateView都是通过ViewRootImpl来执行的,调用流程为WindowManagerImpl -> WindowManagerGlobal -> ViewRootImpl
  4. ViewRootImpl的setView方法中会通过WindowSession的addToDisplay方法完成Window的添加
  5. WindowSession是一个Binder对象,实现类是Session,也就是说addToDisplay其实是一次IPC过程,调用了远程Session中的addToDisplay方法
  6. Session中的addToDisplay中又调用WindowManagerService的addWindow方法,即Window的添加请求最终是通过WindowManagerService来添加的。
  7. 在Activity的setContentView被调用的时候窗口还没有被添加到WindowManager中,只有在调用了Activity的handleResumeActivity方法才会将DecorView添加到WindowManager中。
  8. ViewRootImpl与Choreograhper配合负责执行View的绘制流程
  9. ImputManagerService->ViewRootimpl配合Choreograhper处理触摸事件的传递

ViewRootImpl 核心功能有以下几点:

  • 连接 View 与 WindowManager: 作为 DecorView 的管理者,负责将视图层级树与 WindowManager 关联,通过 setView() 方法将 DecorView 添加到 WMS;
  • 视图绘制管理
    • 基于 Choreographer 实现 VSync 同步,优化绘制性能
    • 触发测量(Measure)、布局(Layout)、绘制(Draw)流程,通过 performTraversals() 方法协调三大过程视图绘制管理​ 负责 View 的刷新及 View 绘制流程的调用;
  • 事件分发​: 接收系统输入事件(如触摸、按键),通过 dispatchInputEvent() 分发给视图树处理
  • 图形表面管理​: 维护 Surface 对象,通过 SurfaceControl 与 SurfaceFlinger 交互,完成绘制内容的合成与显示
  • 窗口生命周期管理​: 处理窗口的创建、更新、销毁,与 WMS 交互管理窗口属性(如位置、大小、焦点)

ViewRootImpl是一个Android视图层次结构的顶部,是View和WindowManager的桥梁。ViewRootImpl与Choreographer协同完成View的绘制,也负责接收底层的触摸事件和对触摸事件的中转分发。

一、ViewRootImpl与窗口的添加

在WMS中提到WindowManager在添加窗口的时候会调用WindowManagerGlobal代理的addView方法来添加View。

// WindowManagerGlobalpublicvoidaddView(Viewview, ViewGroup.LayoutParamsparams,
Displaydisplay, WindowparentWindow) {
...
ViewRootImplroot;
ViewpanelParentView = null;
...
// 实例化ViewRootImpl root = newViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
//将View添加到ViewRootImpl,开始绘制viewroot.setView(view, wparams, panelParentView);
...
}

WindowManagerGlobal的addView、removeView、UpdateView都是通过ViewRootImpl来执行的。

调用的顺序为 WindowManagerImpl -> WindowManagerGlobal -> ViewRootImpl

而ViewRootImpl的setView如下:

// ViewRootImpl publicvoidsetView(Viewview, WindowManager.LayoutParamsattrs, ViewpanelParentView) {
...
// 添加到Window前先调用requestLayout进行布局,确定收到任何系统事件后重新布局。 // requestLayout方法会完成View的绘制流程 requestLayout();
...
try {
...
// 通过WindowSession完成Window的添加res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
} }

mWindowSession类型是IWindowSession,它是一个Binder对象,真正的实现类是Session,也就是说这其实是一次IPC过程,远程调用了Session中的addToDisPlay方法。

@OverridepublicintaddToDisplay(IWindowwindow, intseq, WindowManager.LayoutParamsattrs,
intviewVisibility, intdisplayId, RectoutContentInsets, RectoutStableInsets,
RectoutOutsets, InputChanneloutInputChannel) {
returnmService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outStableInsets, outOutsets, outInputChannel);
}

这里的mService就是WindowManagerService,也就是说Window的添加请求,最终是通过WindowManagerService来添加的。

Activity中的Window与ViewRootImpl

Activity的setContentView被调用时窗口还未被添加到WindowManager中,也就是此时的View不会开启测量绘制流程。当Activity的handleResumeActivity方法被调用时才会将DecorView添加到WindowManager。而在windowManager.addView方法中调用到windowManagerGlobal.addView,开始创建初始化ViewRootImpl。也就是上面添加Window的过程。

二、ViewRootImpl与View的绘制

ViewRootImpl的requestLayout开启View的绘制流程:

@OverridepublicvoidrequestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
// 检查线程是不是主线程,不是主线程则抛出异常checkThread();
mLayoutRequested = true;
// 开启绘制流程scheduleTraversals();
}
}
voidscheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 通过Handler发送同步屏障消息mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 通过Choreographer发送一个Runnable,Choreographer接收到Vsync信号后通过异步消息执行RunnablemChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
...
}
finalclassTraversalRunnableimplementsRunnable {
@Overridepublicvoidrun() {
// 调用doTraversal开启View的绘制doTraversal();
}
}
voiddoTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
// 移除同步屏障,让非异步消息能够执行mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
// 在这里开启View的测量、布局、绘制三大流程performTraversals();
...
}
}
privatevoidperformTraversals() { // 测量 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
// 布局performLayout(lp, desiredWindowWidth, desiredWindowHeight);
// 绘制performDraw();
}
...
} 

三、ViewRootImpl与事件分发

关于触摸事件时如何从驱动到APP的过程可以参考InputManagerService

ViewRootImpl接收到输入事件,

publicvoiddispatchInputEvent(InputEventevent, InputEventReceiverreceiver) {
// InputEvent是接收到的输入事件,可能是KeyEvent,也可能是MotionEvent// InputEventReceiver用来接收输入事件SomeArgsargs = SomeArgs.obtain();
args.arg1 = event;
args.arg2 = receiver;
// MSG_DISPATCH_INPUT_EVENTMessagemsg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
msg.setAsynchronous(true);
// 通过Handler将消息发送到UI线程mHandler.sendMessage(msg);
}

mHandler是ViewRootImpl的内部类ViewRootHandler,在接收到上述消息后对消息进行处理

finalclassViewRootHandlerextendsHandler {
...
@OverridepublicvoidhandleMessage(Messagemsg) {
switch (msg.what) {
...
caseMSG_DISPATCH_INPUT_EVENT: {
SomeArgsargs = (SomeArgs)msg.obj;
InputEventevent = (InputEvent)args.arg1;
InputEventReceiverreceiver = (InputEventReceiver)args.arg2;
// 在UI线程中调用enqueueInputEventenqueueInputEvent(event, receiver, 0, true);
args.recycle();
} break;
...
}
}
}
voidenqueueInputEvent(InputEventevent,
InputEventReceiverreceiver, intflags, booleanprocessImmediately) {
adjustInputEventForCompatibility(event);
//将当前输入事件加入队列中排列等候执行QueuedInputEventq = obtainQueuedInputEvent(event, receiver, flags);
//输入事件添加进队列后,加入输入事件的默认尾部QueuedInputEventlast = mPendingInputEventTail;
if (last == null) {
mPendingInputEventHead = q;
mPendingInputEventTail = q;
} else {
last.mNext = q;
mPendingInputEventTail = q;
}
//队列计数mPendingInputEventCount += 1;
...
//processImmediately则是判断是同步还是异步,前面我们在handler中调用的,因为是在UI线程,肯定是同步的,所以传递了参数是true,如果是异步,则调用到scheduleProcessInputEvents()if (processImmediately) {
// 循环获取队列中的输入事件doProcessInputEvents();
} else {
// 最终通过Handler post出来,还是调用doProcessInputEvents方法scheduleProcessInputEvents();
}
}

上述代码是将消息封装成QueuedInputEvent,并加入链表的操作。QueuedInputEvent是一个链表结构,代码如下:

privatestaticfinalclassQueuedInputEvent {
...
publicQueuedInputEventmNext;
publicInputEventmEvent;
publicInputEventReceivermReceiver;
...
}

doProcessInputEvents代码如下:

voiddoProcessInputEvents() {
//循环取出队列中的输入事件while (mPendingInputEventHead != null) {
QueuedInputEventq = mPendingInputEventHead;
mPendingInputEventHead = q.mNext;
...
mPendingInputEventCount -= 1;
...
//分发处理deliverInputEvent(q);
}
//处理完所有输入事件,清楚标志if (mProcessInputEventsScheduled) {
mProcessInputEventsScheduled = false;
mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
}
}

通过deliverInputEvent进行分发:

privatevoiddeliverInputEvent(QueuedInputEventq) {
//校验输入事件if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
}
InputStagestage;
if (q.shouldSendToSynthesizer()) {
stage = mSyntheticInputStage;
} else {
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
}
if (stage != null) {
stage.deliver(q);
} else {
finishInputEvent(q);
}
}

这里InputStage则是一个实现处理输入事件责任的阶段,提供一系列处理输入事件的方法。每种InputStage可以处理一定的事件类型,比如AsyncInputStage、ViewPreImeInputStage、ViewPostImeInputStage等。当一个InputEvent到来时,ViewRootImpl会寻找合适它的InputStage来处理。

InputStage会先调用deliver开始处理,最终调用onProcess方法。对于View的点击事件可以用ViewPostImeInputStage来处理,它的onProcess方法如下:

@OverrideprotectedintonProcess(QueuedInputEventq) {
if (q.mEventinstanceofKeyEvent) {
returnprocessKeyEvent(q);
} else {
// If delivering a new non-key event, make sure the window is// now allowed to start updating.handleDispatchWindowAnimationStopped();
finalintsource = q.mEvent.getSource();
if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
// 判断是触摸事件调用该方法returnprocessPointerEvent(q);
} elseif ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
returnprocessTrackballEvent(q);
} else {
returnprocessGenericMotionEvent(q);
}
}
}
privateintprocessPointerEvent(QueuedInputEventq) {
// 触摸事件finalMotionEventevent = (MotionEvent)q.mEvent;
mAttachInfo.mUnbufferedDispatchRequested = false;
// 调用DocerView的dispatchPointerEvent,将分发事件交给Viewbooleanhandled = mView.dispatchPointerEvent(event);
...
returnhandled ? FINISH_HANDLED : FORWARD;
}

View的dispatchPointerEvent代码如下:

publicfinalbooleandispatchPointerEvent(MotionEventevent) {
if (event.isTouchEvent()) {
// 如果是TouchEvent,则开启事件分发returndispatchTouchEvent(event);
} else {
returndispatchGenericMotionEvent(event);
}
}

https://www.jianshu.com/p/9da7bfe18374

https://www.jianshu.com/p/9e6c54739217

公众号:玩转安卓Dev

Java基础

面向对象与Java基础知识

Java集合框架

JVM

多线程与并发

设计模式

Kotlin

Android

项目相关问题

Android基础知识

Android消息机制

Android Binder

View事件分发机制

Android屏幕刷新机制

View的绘制流程

Activity启动

Framework

性能优化

Jetpack&系统View

第三方框架实现原理

计算机网络

算法

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' ViewRootImpl · zhpanvip/AndroidNote Wiki · GitHub
Skip to content

ViewRootImpl

ZhangPan edited this page Jul 23, 2025 · 9 revisions

ViewRootImpl概述

  1. WindowManager在添加窗口的时候会通过WindowManagerGlobal代理的addView方法来添加View
  2. 在这个addView方法中会实例化ViewRootImpl,并且通过ViewRootImpl.setView将Window的LayoutParams以及DecoreView传递给ViewRootImpl.
  3. WindowManagerGlobal的addView、removeView、updateView都是通过ViewRootImpl来执行的,调用流程为WindowManagerImpl -> WindowManagerGlobal -> ViewRootImpl
  4. ViewRootImpl的setView方法中会通过WindowSession的addToDisplay方法完成Window的添加
  5. WindowSession是一个Binder对象,实现类是Session,也就是说addToDisplay其实是一次IPC过程,调用了远程Session中的addToDisplay方法
  6. Session中的addToDisplay中又调用WindowManagerService的addWindow方法,即Window的添加请求最终是通过WindowManagerService来添加的。
  7. 在Activity的setContentView被调用的时候窗口还没有被添加到WindowManager中,只有在调用了Activity的handleResumeActivity方法才会将DecorView添加到WindowManager中。
  8. ViewRootImpl与Choreograhper配合负责执行View的绘制流程
  9. ImputManagerService->ViewRootimpl配合Choreograhper处理触摸事件的传递

ViewRootImpl 核心功能有以下几点:

  • 连接 View 与 WindowManager: 作为 DecorView 的管理者,负责将视图层级树与 WindowManager 关联,通过 setView() 方法将 DecorView 添加到 WMS;
  • 视图绘制管理
    • 基于 Choreographer 实现 VSync 同步,优化绘制性能
    • 触发测量(Measure)、布局(Layout)、绘制(Draw)流程,通过 performTraversals() 方法协调三大过程视图绘制管理​ 负责 View 的刷新及 View 绘制流程的调用;
  • 事件分发​: 接收系统输入事件(如触摸、按键),通过 dispatchInputEvent() 分发给视图树处理
  • 图形表面管理​: 维护 Surface 对象,通过 SurfaceControl 与 SurfaceFlinger 交互,完成绘制内容的合成与显示
  • 窗口生命周期管理​: 处理窗口的创建、更新、销毁,与 WMS 交互管理窗口属性(如位置、大小、焦点)

ViewRootImpl是一个Android视图层次结构的顶部,是View和WindowManager的桥梁。ViewRootImpl与Choreographer协同完成View的绘制,也负责接收底层的触摸事件和对触摸事件的中转分发。

一、ViewRootImpl与窗口的添加

在WMS中提到WindowManager在添加窗口的时候会调用WindowManagerGlobal代理的addView方法来添加View。

// WindowManagerGlobalpublicvoidaddView(Viewview, ViewGroup.LayoutParamsparams,
Displaydisplay, WindowparentWindow) {
...
ViewRootImplroot;
ViewpanelParentView = null;
...
// 实例化ViewRootImpl root = newViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
//将View添加到ViewRootImpl,开始绘制viewroot.setView(view, wparams, panelParentView);
...
}

WindowManagerGlobal的addView、removeView、UpdateView都是通过ViewRootImpl来执行的。

调用的顺序为 WindowManagerImpl -> WindowManagerGlobal -> ViewRootImpl

而ViewRootImpl的setView如下:

// ViewRootImpl publicvoidsetView(Viewview, WindowManager.LayoutParamsattrs, ViewpanelParentView) {
...
// 添加到Window前先调用requestLayout进行布局,确定收到任何系统事件后重新布局。 // requestLayout方法会完成View的绘制流程 requestLayout();
...
try {
...
// 通过WindowSession完成Window的添加res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
} }

mWindowSession类型是IWindowSession,它是一个Binder对象,真正的实现类是Session,也就是说这其实是一次IPC过程,远程调用了Session中的addToDisPlay方法。

@OverridepublicintaddToDisplay(IWindowwindow, intseq, WindowManager.LayoutParamsattrs,
intviewVisibility, intdisplayId, RectoutContentInsets, RectoutStableInsets,
RectoutOutsets, InputChanneloutInputChannel) {
returnmService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outStableInsets, outOutsets, outInputChannel);
}

这里的mService就是WindowManagerService,也就是说Window的添加请求,最终是通过WindowManagerService来添加的。

Activity中的Window与ViewRootImpl

Activity的setContentView被调用时窗口还未被添加到WindowManager中,也就是此时的View不会开启测量绘制流程。当Activity的handleResumeActivity方法被调用时才会将DecorView添加到WindowManager。而在windowManager.addView方法中调用到windowManagerGlobal.addView,开始创建初始化ViewRootImpl。也就是上面添加Window的过程。

二、ViewRootImpl与View的绘制

ViewRootImpl的requestLayout开启View的绘制流程:

@OverridepublicvoidrequestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
// 检查线程是不是主线程,不是主线程则抛出异常checkThread();
mLayoutRequested = true;
// 开启绘制流程scheduleTraversals();
}
}
voidscheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 通过Handler发送同步屏障消息mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 通过Choreographer发送一个Runnable,Choreographer接收到Vsync信号后通过异步消息执行RunnablemChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
...
}
finalclassTraversalRunnableimplementsRunnable {
@Overridepublicvoidrun() {
// 调用doTraversal开启View的绘制doTraversal();
}
}
voiddoTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
// 移除同步屏障,让非异步消息能够执行mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
// 在这里开启View的测量、布局、绘制三大流程performTraversals();
...
}
}
privatevoidperformTraversals() { // 测量 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
// 布局performLayout(lp, desiredWindowWidth, desiredWindowHeight);
// 绘制performDraw();
}
...
} 

三、ViewRootImpl与事件分发

关于触摸事件时如何从驱动到APP的过程可以参考InputManagerService

ViewRootImpl接收到输入事件,

publicvoiddispatchInputEvent(InputEventevent, InputEventReceiverreceiver) {
// InputEvent是接收到的输入事件,可能是KeyEvent,也可能是MotionEvent// InputEventReceiver用来接收输入事件SomeArgsargs = SomeArgs.obtain();
args.arg1 = event;
args.arg2 = receiver;
// MSG_DISPATCH_INPUT_EVENTMessagemsg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
msg.setAsynchronous(true);
// 通过Handler将消息发送到UI线程mHandler.sendMessage(msg);
}

mHandler是ViewRootImpl的内部类ViewRootHandler,在接收到上述消息后对消息进行处理

finalclassViewRootHandlerextendsHandler {
...
@OverridepublicvoidhandleMessage(Messagemsg) {
switch (msg.what) {
...
caseMSG_DISPATCH_INPUT_EVENT: {
SomeArgsargs = (SomeArgs)msg.obj;
InputEventevent = (InputEvent)args.arg1;
InputEventReceiverreceiver = (InputEventReceiver)args.arg2;
// 在UI线程中调用enqueueInputEventenqueueInputEvent(event, receiver, 0, true);
args.recycle();
} break;
...
}
}
}
voidenqueueInputEvent(InputEventevent,
InputEventReceiverreceiver, intflags, booleanprocessImmediately) {
adjustInputEventForCompatibility(event);
//将当前输入事件加入队列中排列等候执行QueuedInputEventq = obtainQueuedInputEvent(event, receiver, flags);
//输入事件添加进队列后,加入输入事件的默认尾部QueuedInputEventlast = mPendingInputEventTail;
if (last == null) {
mPendingInputEventHead = q;
mPendingInputEventTail = q;
} else {
last.mNext = q;
mPendingInputEventTail = q;
}
//队列计数mPendingInputEventCount += 1;
...
//processImmediately则是判断是同步还是异步,前面我们在handler中调用的,因为是在UI线程,肯定是同步的,所以传递了参数是true,如果是异步,则调用到scheduleProcessInputEvents()if (processImmediately) {
// 循环获取队列中的输入事件doProcessInputEvents();
} else {
// 最终通过Handler post出来,还是调用doProcessInputEvents方法scheduleProcessInputEvents();
}
}

上述代码是将消息封装成QueuedInputEvent,并加入链表的操作。QueuedInputEvent是一个链表结构,代码如下:

privatestaticfinalclassQueuedInputEvent {
...
publicQueuedInputEventmNext;
publicInputEventmEvent;
publicInputEventReceivermReceiver;
...
}

doProcessInputEvents代码如下:

voiddoProcessInputEvents() {
//循环取出队列中的输入事件while (mPendingInputEventHead != null) {
QueuedInputEventq = mPendingInputEventHead;
mPendingInputEventHead = q.mNext;
...
mPendingInputEventCount -= 1;
...
//分发处理deliverInputEvent(q);
}
//处理完所有输入事件,清楚标志if (mProcessInputEventsScheduled) {
mProcessInputEventsScheduled = false;
mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
}
}

通过deliverInputEvent进行分发:

privatevoiddeliverInputEvent(QueuedInputEventq) {
//校验输入事件if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
}
InputStagestage;
if (q.shouldSendToSynthesizer()) {
stage = mSyntheticInputStage;
} else {
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
}
if (stage != null) {
stage.deliver(q);
} else {
finishInputEvent(q);
}
}

这里InputStage则是一个实现处理输入事件责任的阶段,提供一系列处理输入事件的方法。每种InputStage可以处理一定的事件类型,比如AsyncInputStage、ViewPreImeInputStage、ViewPostImeInputStage等。当一个InputEvent到来时,ViewRootImpl会寻找合适它的InputStage来处理。

InputStage会先调用deliver开始处理,最终调用onProcess方法。对于View的点击事件可以用ViewPostImeInputStage来处理,它的onProcess方法如下:

@OverrideprotectedintonProcess(QueuedInputEventq) {
if (q.mEventinstanceofKeyEvent) {
returnprocessKeyEvent(q);
} else {
// If delivering a new non-key event, make sure the window is// now allowed to start updating.handleDispatchWindowAnimationStopped();
finalintsource = q.mEvent.getSource();
if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
// 判断是触摸事件调用该方法returnprocessPointerEvent(q);
} elseif ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
returnprocessTrackballEvent(q);
} else {
returnprocessGenericMotionEvent(q);
}
}
}
privateintprocessPointerEvent(QueuedInputEventq) {
// 触摸事件finalMotionEventevent = (MotionEvent)q.mEvent;
mAttachInfo.mUnbufferedDispatchRequested = false;
// 调用DocerView的dispatchPointerEvent,将分发事件交给Viewbooleanhandled = mView.dispatchPointerEvent(event);
...
returnhandled ? FINISH_HANDLED : FORWARD;
}

View的dispatchPointerEvent代码如下:

publicfinalbooleandispatchPointerEvent(MotionEventevent) {
if (event.isTouchEvent()) {
// 如果是TouchEvent,则开启事件分发returndispatchTouchEvent(event);
} else {
returndispatchGenericMotionEvent(event);
}
}

https://www.jianshu.com/p/9da7bfe18374

https://www.jianshu.com/p/9e6c54739217

公众号:玩转安卓Dev

Java基础

面向对象与Java基础知识

Java集合框架

JVM

多线程与并发

设计模式

Kotlin

Android

项目相关问题

Android基础知识

Android消息机制

Android Binder

View事件分发机制

Android屏幕刷新机制

View的绘制流程

Activity启动

Framework

性能优化

Jetpack&系统View

第三方框架实现原理

计算机网络

算法

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' ViewRootImpl · zhpanvip/AndroidNote Wiki · GitHub
Skip to content

ViewRootImpl

ZhangPan edited this page Jul 23, 2025 · 9 revisions

ViewRootImpl概述

  1. WindowManager在添加窗口的时候会通过WindowManagerGlobal代理的addView方法来添加View
  2. 在这个addView方法中会实例化ViewRootImpl,并且通过ViewRootImpl.setView将Window的LayoutParams以及DecoreView传递给ViewRootImpl.
  3. WindowManagerGlobal的addView、removeView、updateView都是通过ViewRootImpl来执行的,调用流程为WindowManagerImpl -> WindowManagerGlobal -> ViewRootImpl
  4. ViewRootImpl的setView方法中会通过WindowSession的addToDisplay方法完成Window的添加
  5. WindowSession是一个Binder对象,实现类是Session,也就是说addToDisplay其实是一次IPC过程,调用了远程Session中的addToDisplay方法
  6. Session中的addToDisplay中又调用WindowManagerService的addWindow方法,即Window的添加请求最终是通过WindowManagerService来添加的。
  7. 在Activity的setContentView被调用的时候窗口还没有被添加到WindowManager中,只有在调用了Activity的handleResumeActivity方法才会将DecorView添加到WindowManager中。
  8. ViewRootImpl与Choreograhper配合负责执行View的绘制流程
  9. ImputManagerService->ViewRootimpl配合Choreograhper处理触摸事件的传递

ViewRootImpl 核心功能有以下几点:

  • 连接 View 与 WindowManager: 作为 DecorView 的管理者,负责将视图层级树与 WindowManager 关联,通过 setView() 方法将 DecorView 添加到 WMS;
  • 视图绘制管理
    • 基于 Choreographer 实现 VSync 同步,优化绘制性能
    • 触发测量(Measure)、布局(Layout)、绘制(Draw)流程,通过 performTraversals() 方法协调三大过程视图绘制管理​ 负责 View 的刷新及 View 绘制流程的调用;
  • 事件分发​: 接收系统输入事件(如触摸、按键),通过 dispatchInputEvent() 分发给视图树处理
  • 图形表面管理​: 维护 Surface 对象,通过 SurfaceControl 与 SurfaceFlinger 交互,完成绘制内容的合成与显示
  • 窗口生命周期管理​: 处理窗口的创建、更新、销毁,与 WMS 交互管理窗口属性(如位置、大小、焦点)

ViewRootImpl是一个Android视图层次结构的顶部,是View和WindowManager的桥梁。ViewRootImpl与Choreographer协同完成View的绘制,也负责接收底层的触摸事件和对触摸事件的中转分发。

一、ViewRootImpl与窗口的添加

在WMS中提到WindowManager在添加窗口的时候会调用WindowManagerGlobal代理的addView方法来添加View。

// WindowManagerGlobalpublicvoidaddView(Viewview, ViewGroup.LayoutParamsparams,
Displaydisplay, WindowparentWindow) {
...
ViewRootImplroot;
ViewpanelParentView = null;
...
// 实例化ViewRootImpl root = newViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
//将View添加到ViewRootImpl,开始绘制viewroot.setView(view, wparams, panelParentView);
...
}

WindowManagerGlobal的addView、removeView、UpdateView都是通过ViewRootImpl来执行的。

调用的顺序为 WindowManagerImpl -> WindowManagerGlobal -> ViewRootImpl

而ViewRootImpl的setView如下:

// ViewRootImpl publicvoidsetView(Viewview, WindowManager.LayoutParamsattrs, ViewpanelParentView) {
...
// 添加到Window前先调用requestLayout进行布局,确定收到任何系统事件后重新布局。 // requestLayout方法会完成View的绘制流程 requestLayout();
...
try {
...
// 通过WindowSession完成Window的添加res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
} }

mWindowSession类型是IWindowSession,它是一个Binder对象,真正的实现类是Session,也就是说这其实是一次IPC过程,远程调用了Session中的addToDisPlay方法。

@OverridepublicintaddToDisplay(IWindowwindow, intseq, WindowManager.LayoutParamsattrs,
intviewVisibility, intdisplayId, RectoutContentInsets, RectoutStableInsets,
RectoutOutsets, InputChanneloutInputChannel) {
returnmService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outStableInsets, outOutsets, outInputChannel);
}

这里的mService就是WindowManagerService,也就是说Window的添加请求,最终是通过WindowManagerService来添加的。

Activity中的Window与ViewRootImpl

Activity的setContentView被调用时窗口还未被添加到WindowManager中,也就是此时的View不会开启测量绘制流程。当Activity的handleResumeActivity方法被调用时才会将DecorView添加到WindowManager。而在windowManager.addView方法中调用到windowManagerGlobal.addView,开始创建初始化ViewRootImpl。也就是上面添加Window的过程。

二、ViewRootImpl与View的绘制

ViewRootImpl的requestLayout开启View的绘制流程:

@OverridepublicvoidrequestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
// 检查线程是不是主线程,不是主线程则抛出异常checkThread();
mLayoutRequested = true;
// 开启绘制流程scheduleTraversals();
}
}
voidscheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 通过Handler发送同步屏障消息mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 通过Choreographer发送一个Runnable,Choreographer接收到Vsync信号后通过异步消息执行RunnablemChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
...
}
finalclassTraversalRunnableimplementsRunnable {
@Overridepublicvoidrun() {
// 调用doTraversal开启View的绘制doTraversal();
}
}
voiddoTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
// 移除同步屏障,让非异步消息能够执行mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
// 在这里开启View的测量、布局、绘制三大流程performTraversals();
...
}
}
privatevoidperformTraversals() { // 测量 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
// 布局performLayout(lp, desiredWindowWidth, desiredWindowHeight);
// 绘制performDraw();
}
...
} 

三、ViewRootImpl与事件分发

关于触摸事件时如何从驱动到APP的过程可以参考InputManagerService

ViewRootImpl接收到输入事件,

publicvoiddispatchInputEvent(InputEventevent, InputEventReceiverreceiver) {
// InputEvent是接收到的输入事件,可能是KeyEvent,也可能是MotionEvent// InputEventReceiver用来接收输入事件SomeArgsargs = SomeArgs.obtain();
args.arg1 = event;
args.arg2 = receiver;
// MSG_DISPATCH_INPUT_EVENTMessagemsg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
msg.setAsynchronous(true);
// 通过Handler将消息发送到UI线程mHandler.sendMessage(msg);
}

mHandler是ViewRootImpl的内部类ViewRootHandler,在接收到上述消息后对消息进行处理

finalclassViewRootHandlerextendsHandler {
...
@OverridepublicvoidhandleMessage(Messagemsg) {
switch (msg.what) {
...
caseMSG_DISPATCH_INPUT_EVENT: {
SomeArgsargs = (SomeArgs)msg.obj;
InputEventevent = (InputEvent)args.arg1;
InputEventReceiverreceiver = (InputEventReceiver)args.arg2;
// 在UI线程中调用enqueueInputEventenqueueInputEvent(event, receiver, 0, true);
args.recycle();
} break;
...
}
}
}
voidenqueueInputEvent(InputEventevent,
InputEventReceiverreceiver, intflags, booleanprocessImmediately) {
adjustInputEventForCompatibility(event);
//将当前输入事件加入队列中排列等候执行QueuedInputEventq = obtainQueuedInputEvent(event, receiver, flags);
//输入事件添加进队列后,加入输入事件的默认尾部QueuedInputEventlast = mPendingInputEventTail;
if (last == null) {
mPendingInputEventHead = q;
mPendingInputEventTail = q;
} else {
last.mNext = q;
mPendingInputEventTail = q;
}
//队列计数mPendingInputEventCount += 1;
...
//processImmediately则是判断是同步还是异步,前面我们在handler中调用的,因为是在UI线程,肯定是同步的,所以传递了参数是true,如果是异步,则调用到scheduleProcessInputEvents()if (processImmediately) {
// 循环获取队列中的输入事件doProcessInputEvents();
} else {
// 最终通过Handler post出来,还是调用doProcessInputEvents方法scheduleProcessInputEvents();
}
}

上述代码是将消息封装成QueuedInputEvent,并加入链表的操作。QueuedInputEvent是一个链表结构,代码如下:

privatestaticfinalclassQueuedInputEvent {
...
publicQueuedInputEventmNext;
publicInputEventmEvent;
publicInputEventReceivermReceiver;
...
}

doProcessInputEvents代码如下:

voiddoProcessInputEvents() {
//循环取出队列中的输入事件while (mPendingInputEventHead != null) {
QueuedInputEventq = mPendingInputEventHead;
mPendingInputEventHead = q.mNext;
...
mPendingInputEventCount -= 1;
...
//分发处理deliverInputEvent(q);
}
//处理完所有输入事件,清楚标志if (mProcessInputEventsScheduled) {
mProcessInputEventsScheduled = false;
mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
}
}

通过deliverInputEvent进行分发:

privatevoiddeliverInputEvent(QueuedInputEventq) {
//校验输入事件if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
}
InputStagestage;
if (q.shouldSendToSynthesizer()) {
stage = mSyntheticInputStage;
} else {
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
}
if (stage != null) {
stage.deliver(q);
} else {
finishInputEvent(q);
}
}

这里InputStage则是一个实现处理输入事件责任的阶段,提供一系列处理输入事件的方法。每种InputStage可以处理一定的事件类型,比如AsyncInputStage、ViewPreImeInputStage、ViewPostImeInputStage等。当一个InputEvent到来时,ViewRootImpl会寻找合适它的InputStage来处理。

InputStage会先调用deliver开始处理,最终调用onProcess方法。对于View的点击事件可以用ViewPostImeInputStage来处理,它的onProcess方法如下:

@OverrideprotectedintonProcess(QueuedInputEventq) {
if (q.mEventinstanceofKeyEvent) {
returnprocessKeyEvent(q);
} else {
// If delivering a new non-key event, make sure the window is// now allowed to start updating.handleDispatchWindowAnimationStopped();
finalintsource = q.mEvent.getSource();
if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
// 判断是触摸事件调用该方法returnprocessPointerEvent(q);
} elseif ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
returnprocessTrackballEvent(q);
} else {
returnprocessGenericMotionEvent(q);
}
}
}
privateintprocessPointerEvent(QueuedInputEventq) {
// 触摸事件finalMotionEventevent = (MotionEvent)q.mEvent;
mAttachInfo.mUnbufferedDispatchRequested = false;
// 调用DocerView的dispatchPointerEvent,将分发事件交给Viewbooleanhandled = mView.dispatchPointerEvent(event);
...
returnhandled ? FINISH_HANDLED : FORWARD;
}

View的dispatchPointerEvent代码如下:

publicfinalbooleandispatchPointerEvent(MotionEventevent) {
if (event.isTouchEvent()) {
// 如果是TouchEvent,则开启事件分发returndispatchTouchEvent(event);
} else {
returndispatchGenericMotionEvent(event);
}
}

https://www.jianshu.com/p/9da7bfe18374

https://www.jianshu.com/p/9e6c54739217

公众号:玩转安卓Dev

Java基础

面向对象与Java基础知识

Java集合框架

JVM

多线程与并发

设计模式

Kotlin

Android

项目相关问题

Android基础知识

Android消息机制

Android Binder

View事件分发机制

Android屏幕刷新机制

View的绘制流程

Activity启动

Framework

性能优化

Jetpack&系统View

第三方框架实现原理

计算机网络

算法

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); ViewRootImpl · zhpanvip/AndroidNote Wiki · GitHub
Skip to content

ViewRootImpl

ZhangPan edited this page Jul 23, 2025 · 9 revisions

ViewRootImpl概述

  1. WindowManager在添加窗口的时候会通过WindowManagerGlobal代理的addView方法来添加View
  2. 在这个addView方法中会实例化ViewRootImpl,并且通过ViewRootImpl.setView将Window的LayoutParams以及DecoreView传递给ViewRootImpl.
  3. WindowManagerGlobal的addView、removeView、updateView都是通过ViewRootImpl来执行的,调用流程为WindowManagerImpl -> WindowManagerGlobal -> ViewRootImpl
  4. ViewRootImpl的setView方法中会通过WindowSession的addToDisplay方法完成Window的添加
  5. WindowSession是一个Binder对象,实现类是Session,也就是说addToDisplay其实是一次IPC过程,调用了远程Session中的addToDisplay方法
  6. Session中的addToDisplay中又调用WindowManagerService的addWindow方法,即Window的添加请求最终是通过WindowManagerService来添加的。
  7. 在Activity的setContentView被调用的时候窗口还没有被添加到WindowManager中,只有在调用了Activity的handleResumeActivity方法才会将DecorView添加到WindowManager中。
  8. ViewRootImpl与Choreograhper配合负责执行View的绘制流程
  9. ImputManagerService->ViewRootimpl配合Choreograhper处理触摸事件的传递

ViewRootImpl 核心功能有以下几点:

  • 连接 View 与 WindowManager: 作为 DecorView 的管理者,负责将视图层级树与 WindowManager 关联,通过 setView() 方法将 DecorView 添加到 WMS;
  • 视图绘制管理
    • 基于 Choreographer 实现 VSync 同步,优化绘制性能
    • 触发测量(Measure)、布局(Layout)、绘制(Draw)流程,通过 performTraversals() 方法协调三大过程视图绘制管理​ 负责 View 的刷新及 View 绘制流程的调用;
  • 事件分发​: 接收系统输入事件(如触摸、按键),通过 dispatchInputEvent() 分发给视图树处理
  • 图形表面管理​: 维护 Surface 对象,通过 SurfaceControl 与 SurfaceFlinger 交互,完成绘制内容的合成与显示
  • 窗口生命周期管理​: 处理窗口的创建、更新、销毁,与 WMS 交互管理窗口属性(如位置、大小、焦点)

ViewRootImpl是一个Android视图层次结构的顶部,是View和WindowManager的桥梁。ViewRootImpl与Choreographer协同完成View的绘制,也负责接收底层的触摸事件和对触摸事件的中转分发。

一、ViewRootImpl与窗口的添加

在WMS中提到WindowManager在添加窗口的时候会调用WindowManagerGlobal代理的addView方法来添加View。

// WindowManagerGlobalpublicvoidaddView(Viewview, ViewGroup.LayoutParamsparams,
Displaydisplay, WindowparentWindow) {
...
ViewRootImplroot;
ViewpanelParentView = null;
...
// 实例化ViewRootImpl root = newViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
//将View添加到ViewRootImpl,开始绘制viewroot.setView(view, wparams, panelParentView);
...
}

WindowManagerGlobal的addView、removeView、UpdateView都是通过ViewRootImpl来执行的。

调用的顺序为 WindowManagerImpl -> WindowManagerGlobal -> ViewRootImpl

而ViewRootImpl的setView如下:

// ViewRootImpl publicvoidsetView(Viewview, WindowManager.LayoutParamsattrs, ViewpanelParentView) {
...
// 添加到Window前先调用requestLayout进行布局,确定收到任何系统事件后重新布局。 // requestLayout方法会完成View的绘制流程 requestLayout();
...
try {
...
// 通过WindowSession完成Window的添加res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
} }

mWindowSession类型是IWindowSession,它是一个Binder对象,真正的实现类是Session,也就是说这其实是一次IPC过程,远程调用了Session中的addToDisPlay方法。

@OverridepublicintaddToDisplay(IWindowwindow, intseq, WindowManager.LayoutParamsattrs,
intviewVisibility, intdisplayId, RectoutContentInsets, RectoutStableInsets,
RectoutOutsets, InputChanneloutInputChannel) {
returnmService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outStableInsets, outOutsets, outInputChannel);
}

这里的mService就是WindowManagerService,也就是说Window的添加请求,最终是通过WindowManagerService来添加的。

Activity中的Window与ViewRootImpl

Activity的setContentView被调用时窗口还未被添加到WindowManager中,也就是此时的View不会开启测量绘制流程。当Activity的handleResumeActivity方法被调用时才会将DecorView添加到WindowManager。而在windowManager.addView方法中调用到windowManagerGlobal.addView,开始创建初始化ViewRootImpl。也就是上面添加Window的过程。

二、ViewRootImpl与View的绘制

ViewRootImpl的requestLayout开启View的绘制流程:

@OverridepublicvoidrequestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
// 检查线程是不是主线程,不是主线程则抛出异常checkThread();
mLayoutRequested = true;
// 开启绘制流程scheduleTraversals();
}
}
voidscheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 通过Handler发送同步屏障消息mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 通过Choreographer发送一个Runnable,Choreographer接收到Vsync信号后通过异步消息执行RunnablemChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
...
}
finalclassTraversalRunnableimplementsRunnable {
@Overridepublicvoidrun() {
// 调用doTraversal开启View的绘制doTraversal();
}
}
voiddoTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
// 移除同步屏障,让非异步消息能够执行mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
// 在这里开启View的测量、布局、绘制三大流程performTraversals();
...
}
}
privatevoidperformTraversals() { // 测量 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
// 布局performLayout(lp, desiredWindowWidth, desiredWindowHeight);
// 绘制performDraw();
}
...
} 

三、ViewRootImpl与事件分发

关于触摸事件时如何从驱动到APP的过程可以参考InputManagerService

ViewRootImpl接收到输入事件,

publicvoiddispatchInputEvent(InputEventevent, InputEventReceiverreceiver) {
// InputEvent是接收到的输入事件,可能是KeyEvent,也可能是MotionEvent// InputEventReceiver用来接收输入事件SomeArgsargs = SomeArgs.obtain();
args.arg1 = event;
args.arg2 = receiver;
// MSG_DISPATCH_INPUT_EVENTMessagemsg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
msg.setAsynchronous(true);
// 通过Handler将消息发送到UI线程mHandler.sendMessage(msg);
}

mHandler是ViewRootImpl的内部类ViewRootHandler,在接收到上述消息后对消息进行处理

finalclassViewRootHandlerextendsHandler {
...
@OverridepublicvoidhandleMessage(Messagemsg) {
switch (msg.what) {
...
caseMSG_DISPATCH_INPUT_EVENT: {
SomeArgsargs = (SomeArgs)msg.obj;
InputEventevent = (InputEvent)args.arg1;
InputEventReceiverreceiver = (InputEventReceiver)args.arg2;
// 在UI线程中调用enqueueInputEventenqueueInputEvent(event, receiver, 0, true);
args.recycle();
} break;
...
}
}
}
voidenqueueInputEvent(InputEventevent,
InputEventReceiverreceiver, intflags, booleanprocessImmediately) {
adjustInputEventForCompatibility(event);
//将当前输入事件加入队列中排列等候执行QueuedInputEventq = obtainQueuedInputEvent(event, receiver, flags);
//输入事件添加进队列后,加入输入事件的默认尾部QueuedInputEventlast = mPendingInputEventTail;
if (last == null) {
mPendingInputEventHead = q;
mPendingInputEventTail = q;
} else {
last.mNext = q;
mPendingInputEventTail = q;
}
//队列计数mPendingInputEventCount += 1;
...
//processImmediately则是判断是同步还是异步,前面我们在handler中调用的,因为是在UI线程,肯定是同步的,所以传递了参数是true,如果是异步,则调用到scheduleProcessInputEvents()if (processImmediately) {
// 循环获取队列中的输入事件doProcessInputEvents();
} else {
// 最终通过Handler post出来,还是调用doProcessInputEvents方法scheduleProcessInputEvents();
}
}

上述代码是将消息封装成QueuedInputEvent,并加入链表的操作。QueuedInputEvent是一个链表结构,代码如下:

privatestaticfinalclassQueuedInputEvent {
...
publicQueuedInputEventmNext;
publicInputEventmEvent;
publicInputEventReceivermReceiver;
...
}

doProcessInputEvents代码如下:

voiddoProcessInputEvents() {
//循环取出队列中的输入事件while (mPendingInputEventHead != null) {
QueuedInputEventq = mPendingInputEventHead;
mPendingInputEventHead = q.mNext;
...
mPendingInputEventCount -= 1;
...
//分发处理deliverInputEvent(q);
}
//处理完所有输入事件,清楚标志if (mProcessInputEventsScheduled) {
mProcessInputEventsScheduled = false;
mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
}
}

通过deliverInputEvent进行分发:

privatevoiddeliverInputEvent(QueuedInputEventq) {
//校验输入事件if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
}
InputStagestage;
if (q.shouldSendToSynthesizer()) {
stage = mSyntheticInputStage;
} else {
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
}
if (stage != null) {
stage.deliver(q);
} else {
finishInputEvent(q);
}
}

这里InputStage则是一个实现处理输入事件责任的阶段,提供一系列处理输入事件的方法。每种InputStage可以处理一定的事件类型,比如AsyncInputStage、ViewPreImeInputStage、ViewPostImeInputStage等。当一个InputEvent到来时,ViewRootImpl会寻找合适它的InputStage来处理。

InputStage会先调用deliver开始处理,最终调用onProcess方法。对于View的点击事件可以用ViewPostImeInputStage来处理,它的onProcess方法如下:

@OverrideprotectedintonProcess(QueuedInputEventq) {
if (q.mEventinstanceofKeyEvent) {
returnprocessKeyEvent(q);
} else {
// If delivering a new non-key event, make sure the window is// now allowed to start updating.handleDispatchWindowAnimationStopped();
finalintsource = q.mEvent.getSource();
if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
// 判断是触摸事件调用该方法returnprocessPointerEvent(q);
} elseif ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
returnprocessTrackballEvent(q);
} else {
returnprocessGenericMotionEvent(q);
}
}
}
privateintprocessPointerEvent(QueuedInputEventq) {
// 触摸事件finalMotionEventevent = (MotionEvent)q.mEvent;
mAttachInfo.mUnbufferedDispatchRequested = false;
// 调用DocerView的dispatchPointerEvent,将分发事件交给Viewbooleanhandled = mView.dispatchPointerEvent(event);
...
returnhandled ? FINISH_HANDLED : FORWARD;
}

View的dispatchPointerEvent代码如下:

publicfinalbooleandispatchPointerEvent(MotionEventevent) {
if (event.isTouchEvent()) {
// 如果是TouchEvent,则开启事件分发returndispatchTouchEvent(event);
} else {
returndispatchGenericMotionEvent(event);
}
}

https://www.jianshu.com/p/9da7bfe18374

https://www.jianshu.com/p/9e6c54739217

公众号:玩转安卓Dev

Java基础

面向对象与Java基础知识

Java集合框架

JVM

多线程与并发

设计模式

Kotlin

Android

项目相关问题

Android基础知识

Android消息机制

Android Binder

View事件分发机制

Android屏幕刷新机制

View的绘制流程

Activity启动

Framework

性能优化

Jetpack&系统View

第三方框架实现原理

计算机网络

算法

Clone this wiki locally