Activity、Window、PhoneWindow、DecorView、WindowManager、WindowManagerImpl、WindowManagerGlobal、ViewRootImpl这些概念,在日常的Android开发中,几乎全都看不到,但在View的相关操作中,都起着至关重要的关系。
Window/PhoneWindow
Window,窗口,手机/平板等设备屏幕上看到的除状态栏和导航栏以外的整个区域。他是一个抽象类,其具体逻辑由他的子类PhoneWindow去实现。
Window的对象是在创建Activity时的attach()方法中创建的:
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/PhoneWindow对象
mWindow = new PhoneWindow(this, window, activityConfigCallback);
// 给Window设置回调和监听
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);
}
......
// 将当前Activity与WindowManager关联起来,setWindowManager()方法内部会创建WindowManager/WindowManagerImpl对象
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());
}
// 通过 Window 创建 WindowManager。前面以及通过mWindow.setWindowManager()方法创建,这里就直接获取。
mWindowManager = mWindow.getWindowManager();
......
}
因此,可以说,Activity与Window/PhoneWindow是一对一的关系。Window/PhoneWindow负责View的操作;Activity负责与设备、用户,服务之间的交互。
WindowManager
Window/PhoneWindow的对象mWindow是在Activity的创建过程中的attach()中创建的,因此Activity持有Window/PhoneWindow对象。创建完成之后通过调用mWindow.setWindowManager()方法,在setWindowManager()方法内部创建 WindowManager对象;这样在Window/PhoneWindow对象就持有了WindowManager/WindowManagerImpl对象。然后在Activity中,通过mWindowManager = mWindow.getWindowManager(),这应Activity也就持有了WindowManager/WindowManagerImpl对象,
DecorView
Activity通过setContentView()方法在PhoneWindow调用installDecor()方法创建 DecorView,并通过mDecor.setWindow(this)方法将Window/PhoneWindow和DecorView关联起来。这样DecorView和Window/PhoneWindow相互持有彼此的对象。所以Activity可以通过 DecorView 操作Window/PhoneWindow,也可以通过Window/PhoneWindow操作DecorView 中的各个子View。
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window decor,
// when theme attributes and the like are crystalized. Do not check the feature before this happens.
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
......
}
private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
mDecor = generateDecor(-1);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
// Set up decor part of UI to ignore fitsSystemWindows if appropriate.
mDecor.makeOptionalFitsSystemWindows();
final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(R.id.decor_content_parent);
......
}
}
在ActivityThread中,Activity创建成功后,会在ActivityThread的handleResumeActivity()方法中调用makeVisible()方法,让Activity(DecorView)可见。之后的View的add/update/remove等操作由WindowManager来实现:
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason) {
......
// TODO: 将resumeArgs推入活动中以供考虑
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
......
final Activity a = r.activity;
......
// 如果窗口还没有被添加到窗口管理器,并且这个家伙没有完成自己或启动另一个活动,那么继续并添加窗口。
boolean willBeVisible = !a.mStartedActivity;
if (!willBeVisible) {
try {
willBeVisible = ActivityManager.getService().willActivityBeVisible(a.getActivityToken());
} ......
}
// 要加载的Activity的Window为空 && 要加载的Activity没有被finished && 要加载的Activity即将可见。
if (r.window == null && !a.mFinished && willBeVisible) {//向Window添加Activity的布局UI。
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
.......
if (r.mPreserveWindow) {
......
// 通常ViewRoot通过ViewRootImpl中的setView()方法在Activity的addView()方法中设置回调。如果我们要重用装饰视图,
// 我们必须通知ViewRootImpl,回调可能已经改变。
ViewRootImpl impl = decor.getViewRootImpl();
if (impl != null) {
impl.notifyChildRebuilt();
}
}
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
wm.addView(decor, l);// 提交给WindowManager去执行 addView()操作,其实最终执行该操作的是WMS
} else {
// 该activity将在前面获得这个 LayoutParams 更改的回调。然而,在那个时候装饰将不会被设置(这是在这个方法中
// 设置的),所以不会采取任何行动。此调用确保回调与装饰集一起发生。
a.onWindowAttributesChanged(l);
}
}
// 如果窗口已经被添加,但是在恢复期间我们启动了另一个activity,那么还不要使窗口可见。
} else if (!willBeVisible) {
r.hideForNow = true;
}
......
// 如果窗口已经添加,那么它现在是可见的,我们不是简单地完成,也不是开始另一个activity。
if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
......
WindowManager.LayoutParams l = r.window.getAttributes();
if ((l.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != forwardBit) {
l.softInputMode = (l.softInputMode & (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)) | forwardBit;
if (r.activity.mVisibleFromClient) {
ViewManager wm = a.getWindowManager();
View decor = r.window.getDecorView();
wm.updateViewLayout(decor, l);
}
}
......
if (r.activity.mVisibleFromClient) {
r.activity.makeVisible();// Activity可见
}
}
......
}
ViewManager与WindowManagerImpl
WindowManager是一个接口,同时他还继承了ViewManager接口,该接口内部定义了操作View的基本方法:
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
WindowManager接口定义的功能,都由他的实现类WindowManagerImpl去实现,但其实WindowManagerImpl也只是一个中转站,他最后会去调用WindowManagerGlobal来实现各功能。而WindowManagerImpl持有WindowManagerGlobal的单例对象:
public final class WindowManagerImpl implements WindowManager {
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
......
}
也因此,WindowManagerImpl类逻辑很简单,毕竟作为一个操作View的中转站,不用太多的封装。
WindowManagerGlobal
作为View的管理(addView()、updateViewLayout()、removeView())的实际指挥者,WindowManagerGlobal的实现相比WindowManagerImpl复杂很多,主要体现在: a、具体实现对View操作的逻辑:
public void addView(View view, ViewGroup.LayoutParams params) {
......
};
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
......
};
public void removeView(View view) {
......
};
b、统一管理和维护各窗口的View(包括各个Window/PhoneWindow正在使用的View以及被remove移除的Window窗口的View)、ViewRootImpl、WindowManager.LayoutParams:
// 统一管理和维护所有的Window窗口里面的View。
private final ArrayList<View> mViews = new ArrayList<>();
// 统一管理和维护所有的Window窗口里面的ViewRootImpl。
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<>();
// 统一管理和维护所有的Window窗口里面的View的WindowManager.LayoutParams布局参数。
private final ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<>();
// 统一管理和维护所有的被remove移除的Window窗口里面的View。
private final ArraySet<View> mDyingViews = new ArraySet<>();
因此,可以这样理解:WindowManagerGlobal指挥着ViewRootImpl去执行View的addView()、updateViewLayout()、removeView()等操作的执行,同时还统一管理和维护着各个Window/PhoneWindow(一个Window/PhoneWindow对象对应着一个Activity)正在使用的View、ViewRootImpl、WindowManager.LayoutParams以及被移除Window的暂时不用的View(可能被销毁,也可能继续被复用)。
ViewRootImpl
直到这里,真正执行View的addView()、updateViewLayout()、removeView()等操作的主角ViewRootImpl才正式登场。而这些操作最终被提交到WindowManagerService(WMS)来完成。
首先,ViewRootImpl是在Activity被创建之后的onResume()方法阶段被创建的,其调用链是 在ActivityThread中的handleResumeActivity()---->r.activity.makeVisible()---->activity的makeVisible()方法---->wm.addView(mDecor, getWindow().getAttributes())---->WindowManager/WindowManagerImpl的addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params)方法---->WindowManagerGlobal的addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow)方法:
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) {
......
// 这里创建ViewRootImpl对象 root,主要注意的是:一个Window窗口/Activity里面只会有唯一的ViewRootImpl对象。
ViewRootImpl root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);// 将 LayoutParams 布局参数设置给View
mViews.add(view);// ArrayList<View>类型的数组
mRoots.add(root);// ArrayList<ViewRootImpl>类型的数组
mParams.add(wparams);// ArrayList<WindowManager.LayoutParams>类型的数组
....
// 在上面,Window窗口的View、ViewRootImpl、WindowManager.LayoutParams对象都做了统一的保存之后,再在这里执行set操作
try {
// 下面就进入 ViewRootImpl,开始执行View的addView()操作
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
....
}
}
ViewRootImpl的setView()方法实现伪代码如下:
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {// ViewRootImpl与View的关联只能关联执行一次,如果已经关联执行过,就不在执行
mView = view;// 将顶层视图/根布局DecorView赋值给全局的mView对象
// 下面代表的代码都是为了获取View的参数以及Surface对象。并将View和Surface进行绑定。
mAttachInfo.mDisplayState = mDisplay.getState();
mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
mFallbackEventHandler.setView(view);
mWindowAttributes.copyFrom(attrs);
if (mWindowAttributes.packageName == null) {
mWindowAttributes.packageName = mBasePackageName;
}
......
// Keep track of the actual window flags supplied by the client.
mClientWindowLayoutFlags = attrs.flags;
setAccessibilityFocus(null, null);
if (view instanceof RootViewSurfaceTaker) {
mSurfaceHolderCallback = ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
if (mSurfaceHolderCallback != null) {
mSurfaceHolder = new TakenSurfaceHolder();
mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
mSurfaceHolder.addCallback(mSurfaceHolderCallback);
}
}
......
mSoftInputMode = attrs.softInputMode;
mWindowAttributesChanged = true;
mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;
mAttachInfo.mRootView = view;
mAttachInfo.mScalingRequired = mTranslator != null;
mAttachInfo.mApplicationScale = mTranslator == null ? 1.0f : mTranslator.applicationScale;
if (panelParentView != null) {
mAttachInfo.mPanelParentWindowToken = panelParentView.getApplicationWindowToken();
}
mAdded = true;
int res; /* = WindowManagerImpl.ADD_OKAY; */
// 在添加到窗口管理器之前安排执行第一个布局,以确保我们在从系统接收任何其他事件之前进行重新布局。
// TODO:在这里面会执行更新View的线程是否是主线程的检测。
requestLayout();
if ((mWindowAttributes.inputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
mForceDecorViewVisibility = (mWindowAttributes.privateFlags & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
try {
......
// 在这里,开始五WMS通信。这里的mWindowSession是IWindowSession mWindowSession是一个AIDL接口。
// 然后接口实现者是 services\core\java\com\android\server\wm\Session.java路径下的。这个方法里面,
// 没有 看到View的身影:因为向WMS添加的只是参数,诸如Display的Id,LayoutParams布局参数,窗口根布局的可见性,
// 表示窗口布局位置的Rect参数等等
// mWindow 是一个用于Binder通信的AIDL接口,相当于一个回调。类似于Activity启动时的,
// 在attached方法中app端会传一个Proxy的代理过去
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(),
mDisplay.getDisplayId(), mWinFrame, mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
} catch (RemoteException e) {
......
} finally {
......
}
if (mTranslator != null) {
mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
}
// Pending:等待、待决定的
mPendingOverscanInsets.set(0, 0, 0, 0);
mPendingContentInsets.set(mAttachInfo.mContentInsets);
mPendingStableInsets.set(mAttachInfo.mStableInsets);
mPendingDisplayCutout.set(mAttachInfo.mDisplayCutout);
mPendingVisibleInsets.set(0, 0, 0, 0);
mAttachInfo.mAlwaysConsumeNavBar = (res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR) != 0;
mPendingAlwaysConsumeNavBar = mAttachInfo.mAlwaysConsumeNavBar;
if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
......
if (view instanceof RootViewSurfaceTaker) {
mInputQueueCallback = ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
}
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, Looper.myLooper());
}
view.assignParent(this);
mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
if (mAccessibilityManager.isEnabled()) {
mAccessibilityInteractionConnectionManager.ensureConnection();
}
if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
}
......
}
}
}
总结
至此,Activity、Window、PhoneWindow、DecorView、WindowManager、WindowManagerImpl、WindowManagerGlobal、ViewRootImpl的关系总结如下图: