本篇博客主要分析ViewTree的管理者ViewRoot即ViewRootImpl,是怎么工作的。
一,ViewRootImpl与WMS间的双向通信
ViewRootImpl > WMS:IwindowSession
WMS > ViewRootImpl:Iwindow
IwindowSession、Iwindow均是匿名的BindServer。
1. ViewRootImpl获取IWindowSession服务句柄的过程。
ViewRootImpl.java
public ViewRootImpl(Context context, Display display) {
mContext = context;
mWindowSession = WindowManagerGlobal.getWindowSession();
...
}
WindowManagerGlobal.java
@UnsupportedAppUsage
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
// Emulate the legacy behavior. The global instance of InputMethodManager
// was instantiated here.
// TODO(b/116157766): Remove this hack after cleaning up @UnsupportedAppUsage
InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
IWindowManager windowManager = getWindowManagerService();
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
});
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowSession;
}
}
这里的IWindowManager是WindowManagerService在本地进程端的代理,windowManager的请求都是在远程端由WMS实现;
在ActivityThread中,处理handleResumeActivity时,也有一个WindowManager,即:ViewManager wm =a.getWindowManager();这里的wm是ViewManager,它是WindowManager类的基类,最终实现是WindowManagerImpl,是完全属于本地端的,存储与应用进程内部用于窗口管理的相关事务。
2.
在handleResumeActivity中,通过wm.addView(decor,l),最后会调用ViewRootImpl的setView,这个函数一方面把DecorView,也即是viewtree的根设置到ViewRootImpl中,用mView保存;另一方面会向WMS申请注册一个窗口,同时把mWindow对象(W类型,也是ViewRootImpl的内部类,是Iwindow服务端的实现)传给WMS,实现WMS跟Viewroot的通信。
ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
...
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
mTempInsets);
setFrame(mTmpFrame);
} catch (RemoteException e) {
mAdded = false;
mView = null;
mAttachInfo.mRootView = null;
mInputChannel = null;
mFallbackEventHandler.setView(null);
unscheduleTraversals();
setAccessibilityFocus(null, null);
throw new RuntimeException("Adding window failed", e);
} finally {
if (restore) {
attrs.restore();
}
}
...
}
}
}
跟窗口相关的两个概念,phoneWindow继承自Window类,是应用进程端对窗口的描述,表达了对窗口的一种约束;WMS中的window是一个抽象的概念,用WindowState来描述其状态,WindowState可以认为是WMS中对窗口的描述。
二,ViewRootImpl的工作方式
每个ViewTree只对应一个ViewRoot,它将跟WMS进行一系列的通信,包括窗口的注册、大小调整等。什么情况会执行这些操作?
1. ViewTree内部的请求,如view对象要更新UI,它会通过invalidate或者其他方式发起请求,随后这些请求会沿着ViewTree层层网上传递,最终到达ViewRoot,做为ViewTree的管理者它根据一系列实际情况来执行相应操作(如发起一次遍历、通知WMS等)。
2. 外部的状态更新,如WMS回调viewroot通知界面大小改变、触摸事件、按键事件等。
不管是内部请求、还是外部请求,viewroot通常会把这些消息入栈,然后ViewRootImpl中ViewRootHandler类来统一处理他们。ViewRootImpl是在WindowManagerImpl的addView的过程中创建的,addView调用的起点是ActivityThread的handleResumeActivity,所以说ViewRootImpl实际是运行在主线程中,ViewRootHandler实际上会跟主线程的消息队列挂钩。
内外部的请求都先入队到主线程的messagequeue,再有Viewroot具体处理。
ViewRootImpl.java
final class ViewRootHandler extends Handler {
...
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_INVALIDATE:
((View) msg.obj).invalidate();
break;
...
}
}
...
}
来源:CSDN
作者:小人物梦想大世界
链接:https://blog.csdn.net/qq2234385378/article/details/101856019