浅谈Window、WMS和ViewRootImpl
1.window
window标示一个窗口的概念,是一个抽象类。具体实现为phonewindow。android中所有的视图都是通过window来实现的(activity dialog toast等),window并不是实际存在,而是以view的形式存在。在实际使用中,无法直接访问window,对window的访问必须通过windowmanager。
注:每一个Activity都包含一个Window对象,Window对象通常由PhoneWindow实现。
2.windowmanager
windowmanager是外界访问window的入口。
3.windowmanagerservice
window最终的添加,更新,删除会通过ipc调用,交给wms去处理。
4.viewrootimpl
viewrootimpl是链接windowmanager和view的纽带。它实现了View与WindowManager之间所需要的协议。
addView,removeView,update调用顺序
WindowManagerImpl -> WindowManagerGlobal -> ViewRootImpl
5.activity中window的创建过程
前面是模糊的概念,下面分析下acticity中window的创建过程。
window和windowmanager和viewrootimpl创建时机.png
注释1:
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
//ContextImpl的绑定
attachBaseContext(context);
//在当前Activity创建Window
mWindow = new PhoneWindow(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
...
//为Window设置WindowManager
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
//创建完后通过getWindowManager就可以得到WindowManager实例
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
}
在act的attach生命周期中,创建window,windowmanager。
注释2:
在act的oncrete中,setcontenview主要做的事情:
1.里面创建了DecorView,根据Theme,Feature添加了对应的布局文件
2.将r.id.xxxlayout的布局文件添加到decorview的mcontentparent中。(即decorview布局id为content的view中)
3.回调act的oncontentchanged方法通知act视图已经发生了变化。
注释3:这时候需要将decorview添加到window中。通过windowmanager添加。
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
上面把DecorView添加到WindowManager,调用到的是WindowManagerGlobal.addView方法,而该方法中真正把View传递给WindowManager的是通过ViewRoot的setView()方法,ViewRoot实现了View和WindowManager之间的消息传递。
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
...
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
requestLayout();
...
try {
...
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
}
}
其中requestlayout完成view的三大流程(测量 布局 绘制)。
mWindowSession.addToDisplay通过ipc方式向session发送消息,最终通过mws完成window的添加流程。
至此,act中window的创建过程分析结束。
经过上诉分析,除了知道window,windowmanager,wms,viewrootimpl等之间的联系,也能知道日常开发中的一些问题。
1.oncreate为什么可以在子线程刷新ui
viewrootimpl在oncreatre时还没有创建起来(在onresume之后),所以不会检查线程。
2.requestFeature 方法的位置需要放在setContentView方法之前。
在setContentView就会根据act的主题来加载布局。
3.oncreate onresume中获取view宽高为0
另外,wms添加还会验证token,通过对dialog中window创建的分析(自己去分析),dialog需要依附act的token。所以创建dialog只能传递act的context,否则将会报错。
4.拓展: view的事件传递机制(如何从硬件==》mws==》viewrootimpl==》phonewindow==》decorview==》act)