前言
引用一下刚哥关于Window、WindowManager和RootViewImpl的概念
Window表示一个窗口的概念,是一个抽象类,它的具体实现是PhoneWindow,而创建一个Window,只需要通过WindowManager就可完成,WindowManager是外界访问Window的入口,Window的具体实现在WindowMangerService中,WindowManager和WindowMangerService的交互实际上是一个IPC的过程。
android中所有的视图都是通过Window来呈现的,不管是Activity,Dialog或Toast,它们的视图实际上都是附加在Window上面的,因此Window是View的直接管理者,从View的事件分发机制可知,单击事件由Window传递到DecorView,然后再由DecorView传递给View,就连Activity的设置视图的方法setContentView底层也是通过Window完成的
ViewRoot对应于ViewRootImpl,它是连接WindowManager和DecorView之间的纽带,View的measure、layout和draw过程都是由它来完成的
View的事件分发机制传送门
什么时候创建它们
它们的创建要从Activity的启动开始说起,而Activity的启动是一个相当复杂的过程,这篇文章的重点不在这里,所有不会详细分析Activity的启动过程。
当启动一个Activity的时候,我们只需要调用startActivity方法,然后系统会调用一系列startActivity的方法,最终会调用ActivityThread里面的performLaunchActivity方法
try {
//首先通过Instrumentation的newActivity方法使用类加载器创建activity对象
java.lang.ClassLoader cl = appContext . getClassLoader ();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException (
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
...
//通过activity的attach方法,传入window,创建window
activity.attach(
appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback);
继续看一下Activity里面的attach方法,看一下是否创建了Window对象
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,
Window window, ActivityConfigCallback activityConfigCallback) {
...
//创建window对象
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
if (info.uiOptions != 0) {
mWindow.setUiOptions(info.uiOptions);
}
...
//设置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());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
mWindow.setColorMode(info.colorMode);
setAutofillCompatibilityEnabled(application.isAutofillCompatibilityEnabled());
enableAutofillCompatibilityIfNeeded();
}
上面的代码很清晰,通过实例创建window对象,通过context. getSystemService获取WindowManager。
此时window和WindowManager已经创建好,Instrumentation会调用callActivityOnCreate方法,
Instrumentation:
public void callActivityOnCreate(Activity activity, Bundle icicle) {
prePerformCreate(activity);
activity.performCreate(icicle);
postPerformCreate(activity);
}
Activity:
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
mCanEnterPictureInPicture = true;
restoreHasCurrentPermissionRequest(icicle);
//onCreate方法被调用
if (persistentState != null) {
onCreate(icicle, persistentState);
} else {
onCreate(icicle);
}
writeEventLog(LOG_AM_ON_CREATE_CALLED, "performCreate");
mActivityTransitionState.readState(icicle);
mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
com.android.internal.R.styleable.Window_windowNoDisplay, false);
mFragments.dispatchActivityCreated();
mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
}
Activity的onCreate方法被调用,在这个方法中,我们一般会通过setContentView(int layoutId)设置一个contentView
Activity:
public void setContentView(@LayoutRes int layoutResID) {
//通过Window设置contentView
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
PhoneWindow:
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
}
PhoneWindow通过installDecor()方法创建DecorView,此时DecorView也已经就绪,还剩下ViewRoot没有创建。那么它到底是什么时候创建的。这个时候我们继续跟踪ActivityThread的代码,在handleResumeActivity中有这样一句代码
ActivityThread:
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason) {
...
r.activity.makeVisible();
}
Activity:
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
//此时WindowManager将Window添加进来
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
WindowManager是一个接口,它的实现类是WindowManagerImpl,看一下实现类里面addView的代码
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
可以看出WindowManagerImpl并没有实现addView的操作,而是交给了WindowManagerGlobal来处理,WindowManagerGlobal的addView方法主要分为如下几步,
1.检查参数是否合法,如果是子view还需要调整一些布局参数
if (view == null) {
throw new IllegalArgumentException ("view must not be null");
}
if (display == null) {
throw new IllegalArgumentException ("display must not be null");
}
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException ("Params must be WindowManager.LayoutParams");
}
final WindowManager . LayoutParams wparams = (WindowManager.LayoutParams) params;
if (parentWindow != null) {
parentWindow.adjustLayoutParamsForSubWindow(wparams);
}
2.创建ViewRootImpl,将一些对象添加到对应的列表中
//创建ViewRootImpl实例
root = new ViewRootImpl (view.getContext(), display);
view.setLayoutParams(wparams);
//将view、root和params添加到对应的列表中
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
在WindowManagerGlobal中维护了几个比较重要的列表
//存储所有Window所对应的View
private final ArrayList<View> mViews = new ArrayList<View>();
//存储所有Window所对应的ViewRootImpl
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
//存储所有Window所对应的布局参数
private final ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>();
//存储那些正在被删除的View对象,或者说那些已经调用了removeView方法但删除操作还未完成的Window对象
private final ArraySet<View> mDyingViews = new ArraySet<View>();
3.通过ViewRootImpl更新界面并完成Window的添加过程
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
...
requestLayout();
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
res = mWindowSession.addToDisplay(
mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
}
...
}
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
这里我们只看一下核心代码,ViewRootImpl通过requestLayout来完成异步刷新请求,scheduleTraversals()则是View绘制的入口,View绘制的内容也不多说,后续会单独介绍。接着会通过WindowSession完成最终的添加过程,mWindowSession的类型是IWindowSession,是一个Binder对象,真正的实现类是Session,到此Window的添加完成了一次IPC调用
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
Rect outStableInsets, Rect outOutsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
return mService.addWindow(
this, window, seq, attrs, viewVisibility, displayId, outFrame,
outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel);
}
而Session的addToDisplay又调用了WindowManagerService的addWindow来实现添加,至此,Window的添加过程分析完毕,删除过程同添加过程一样,这里就不做分析了。
总结
1. 一个Activity对应一个Window
2. Window是一个抽象的概念,相当于一个容器,内部持有一个DecorView,是一个根view,唯一实现类是PhoneWindow
3. ViewRootImpl完成View的绘制过程
4. ViewRootImpl是View和WindowManager之间的桥梁,View通过WindowManager间接调用ViewRootImpl的方法, ViewRootImpl通过WindowSession单向与WindowManagerService通信,最终通过WindowManagerService完成对View的添加;
5. 通过WindowSession添加view时,传入了一个IWindow的对象,它也是一个Binder对象,WindowManagerService通过IWindow与ViewRootImpl进行单向通信
个人能力有限,如有错误,欢迎指正