前面讲了onCreat中具体做了什么 深入理解Activity的显示原理(1)
接下来看看onResume生命周期中做了什么
Activity.onResume
ActivityThread.java
Java
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
...
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
...
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
...
//1.拿到Activity持有的mWindowManager后调用addView
wm.addView(decor, l);
}
if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
...
if (r.activity.mVisibleFromClient) {
//2.
r.activity.makeVisible();
}
}
...
}
ActivityThread 会根据请求创建管理着四大组件的生命周期方法的调用,onResume生命周期是在ActivityThread的handleResumeActivity方法中去调用的。在这个方法中先是通过performResumeActivity的方式触发了activity的回调,然后判断了activity未关闭而且要显示时,会取出activity的DecorView,把DecorView添加到ViewManager。这个ViewManager其实是Activity持有的一个WindowManager。
最后调用activity的makeVisible方法,把activity设置为可见的。其实makeVisiblel方法所做的仅仅是把activity的DecorView设置为可见状态,这并不足以支撑完成全部的绘制工作,只是触发了一次重绘。所以重点还是要分析addView具体是怎么操作的。
ViewManager.addView
源码
Java
//Activity.java
private WindowManager mWindowManager;
final void attach() {
mWindow = new PhoneWindow(this, window, activityConfigCallback);
//获取WindowManager
mWindowManager = mWindow.getWindowManager();
...
}
--------------------
//Windows.java
public WindowManager getWindowManager() {
return mWindowManager;
}
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated;
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
---------------------
//WindowManagerImpl.java
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
...
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
每个activity在初始化的时候都会持有一个WindowManager。而且是通过每个activity自己的phonewindow的getWindowManager方法来获取的。用于管理Window
上的View
,包括addView
和remove
。
在Windows.java
可以看到用来addView的WindowManager是通过createLocalWindowManager方法自己创建的一个WindowManagerImpl实例。所以接着看WindowManagerImpl类的addView方法,发现最后是调用了WindowManagerGlobal的addView方法。
Java
//WindowManagerGlobal.java
public static WindowManagerGlobal getInstance() {
synchronized (WindowManagerGlobal.class) {
if (sDefaultWindowManager == null) {
sDefaultWindowManager = new WindowManagerGlobal();
}
return sDefaultWindowManager;
}
}
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
...
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
...
root.setView(view, wparams, panelParentView);
}
WindowManagerGlobal是个单例。在调用addView方法之后,如果是首次添加的情况,会创建一个ViewRootImpl实列root,并且把view和root缓存到单例的属性中,最后再调用setView方法。
ViewRootImpl.setView
Java
final W mWindow;
View mView;
final IWindowSession mWindowSession;
static class W extends IWindow.Stub {}
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
if (mView == null) {
mView = view;
...
requestLayout();//触发布局和绘制
...
res = mWindowSession.addToDisplay(mWindow, ...);//通知WMS添加窗口
...
view.assignParent(this);
}
}
mView为空的时候,调用requestLayout方法来触发布局和绘制。
addToDisplay这个方法的作用就是通知WMS添加窗口。调用WMS肯定是跨进程通信,参数中的mWindow是一个W类型的静态内部类,这个类继承了IWindow.Stub用来和WMS进行双向通信。这里用到的mWindowSession,同样是一个跨进程通信的句柄,是一个Binder服务代理,是App端向WMS发送消息的通道。
在方法的最后,调用view的assignParent方法,这个View就是我们上文的DecorView,把decorView的parent设置为了ViewRootImpl。这样做的目的就是让ViewRootImpl能够管理整个viewTree。
总结一下到目前为止的流程。首先在Activity的attach过程中,除了创建了phoneWindow,还为activity创建了一个WindowManager,以便管理整个phoneWindow。在onResume生命周期中,会调用WindowManager的addView添加decorView。那么当WindowManager管理viewTree的时候,会给viewTree分配一个ViewRootImpl。ViewRootImpl的职责就是管理viewTree的绘制工作,包括viewTree的显示、测量、同步刷新以及事件分发等等,和负责与其他的服务进行通信。
WMS通信
在多个 Activity 同时存在的情况下,每个 Activity 都有自己独立的窗口相关对象,包括 PhoneWindow、DecorView 和 WindowManagerImpl。这样可以确保每个 Activity 的窗口操作相互独立,互不干扰。WindowManagerGlobal作为一个全局的单例,持有每个activity的rootView ,mWindowSession和mWindow分别是和WMS进行双向通信的句柄。

总结
Activity的attach方法中会初始化PhoneWindow以及WindowManager,setContentView方法中创建了DecorView,并且把我们自己实现的布局转化成了viewTree挂载在了DecorView的contentParent下面,形成了一个完整的ViewTree。
最后activity的onResume生命周期里,通过addView的方式创建了ViewRootImpl,并且用它来管理viewTree的绘制工作。ViewRootImpl可以理解为"View树的管理者"------它有一个mView成员变量,其指向Window和Activity中共同拥有的mDecor对象,即View树的根DecorView。windowSession以及mWindow是用来和WMS进行双向通信的。最后再通过requestLayout显示activity中的内容。