- Notifications
You must be signed in to change notification settings - Fork 149
ViewRootImpl
- WindowManager在添加窗口的时候会通过WindowManagerGlobal代理的addView方法来添加View
- 在这个addView方法中会实例化ViewRootImpl,并且通过ViewRootImpl.setView将Window的LayoutParams以及DecoreView传递给ViewRootImpl.
- WindowManagerGlobal的addView、removeView、updateView都是通过ViewRootImpl来执行的,调用流程为WindowManagerImpl -> WindowManagerGlobal -> ViewRootImpl
- ViewRootImpl的setView方法中会通过WindowSession的addToDisplay方法完成Window的添加
- WindowSession是一个Binder对象,实现类是Session,也就是说addToDisplay其实是一次IPC过程,调用了远程Session中的addToDisplay方法
- Session中的addToDisplay中又调用WindowManagerService的addWindow方法,即Window的添加请求最终是通过WindowManagerService来添加的。
- 在Activity的setContentView被调用的时候窗口还没有被添加到WindowManager中,只有在调用了Activity的handleResumeActivity方法才会将DecorView添加到WindowManager中。
- ViewRootImpl与Choreograhper配合负责执行View的绘制流程
- 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的绘制,也负责接收底层的触摸事件和对触摸事件的中转分发。
在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的setContentView被调用时窗口还未被添加到WindowManager中,也就是此时的View不会开启测量绘制流程。当Activity的handleResumeActivity方法被调用时才会将DecorView添加到WindowManager。而在windowManager.addView方法中调用到windowManagerGlobal.addView,开始创建初始化ViewRootImpl。也就是上面添加Window的过程。
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();
}
...
} 关于触摸事件时如何从驱动到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);
}
}- JMM与volatile关键字
- synchronized的实现原理
- synchronized等待与唤醒机制
- ReentrantLock的实现原理
- ReentrantLock等待与唤醒机制
- CAS、Unsafe类以及Automic并发包
- ThreadLocal的实现原理
- 线程池的实现原理
- Java线程中断机制
- 多线程与并发常见面试题
- Android基础知识汇总
- MVC、MVP与MVVM
- SparseArray实现原理
- ArrayMap的实现原理
- SharedPreferences
- Bitmap
- Activity的启动模式
- Fragment核心原理
- 组件化项目架构搭建
- 组件化WebView架构搭建
- 为什么 Activity.finish() 之后 10s 才 onDestroy ?
- Android系统启动流程
- InputManagerService
- WindowManagerService
- Choreographer详解
- SurfaceFlinger
- ViewRootImpl
- APP启动流程
- Activity启动流程
- PMS 安装与签名校验
- Dalvik 与 ART
- Glide实现原理
- OkHttp实现原理
- Retrofit实现原理
- RxJava实现原理
- RxJava中的线程切换与线程池
- LeakCanary实现原理
- ButterKnife实现原理
- ARouter实现原理
- Tinker实现原理
- 2. 两数相加
- 19.删除链表的倒数第 N 个结点
- 21. 合并两个有序链表
- 24. 两两交换链表中的节点
- 61. 旋转链表
- 86. 分隔链表
- 92. 反转链表 II
- 141. 环形链表
- 160. 相交链表
- 206. 反转链表
- 206 反转链表 扩展
- 234. 回文链表
- 237. 删除链表中的节点
- 445. 两数相加 II
- 面试题 02.02. 返回倒数第 k 个节点
- 面试题 02.08. 环路检测
- 剑指 Offer 06. 从尾到头打印链表
- 剑指 Offer 18. 删除链表的节点
- 剑指 Offer 22. 链表中倒数第k个节点
- 剑指 Offer 35. 复杂链表的复制
- 1. 两数之和
- 11. 盛最多水的容器
- 53. 最大子序和
- 75. 颜色分类
- 124.验证回文串
- 167. 两数之和 II - 输入有序数组 -169. 多数元素
- 189.旋转数组
- 209. 长度最小的子数组
- 283.移动0
- 303.区域和检索 - 数组不可变
- 338. 比特位计数
- 448. 找到所有数组中消失的数字
- 643.有序数组的平方
- 977. 有序数组的平方



