Window(或者说View) 是怎么添加到 Android 系统中而后展现给用户的?让咱们来探索一下 Window 的添加过程。java
要探索添加的过程,必须先在源代码中找到添加 Window 的入口方法。less
Window 的添加须要经过 WindowManager 的 addView
方法实现,但 WindowManager 是个接口,它的真正实现类是 WindowManagerImpl 类,但 WindowManagerImpl 也并无直接实现对 Window 的添加、删除、更新操做,而是经过桥接模式将全部操做委托给 WindowManagerGlobal 去实现。最终会调用 WindowManagerGlobal 类的 addView
方法真正开启 View 的添加过程。异步
全部,Window 添加过程的真正入口方法其实是 WindowManagerGlobal 类的 addView
方法。ide
WindowManagerGlobal 的 addView
方法主要干了三件事:布局
检查参数 params 是不是 WindowManager.LayoutParams,若是不是说明参数不合法,则会抛出异常。this
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) {
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)) { // 检查 params 参数是否合法
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
...
}
复制代码
建立 ViewRootImpl,并将 View 添加到列表中。spa
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) {
...
root = new ViewRootImpl(view.getContext(), display); // 建立 ViewRootImpl
view.setLayoutParams(wparams);
mViews.add(view); // 将View添加到mView列表中,mView 存储的是全部Window对应的View
mRoots.add(root);
mParams.add(wparams);
...
}
复制代码
经过 ViewRootImpl 的 setView
方法来添加更新界面并经过 IPC 的方式调用 WindowManagerService 的 addWindow
方法完成 Window 的添加过程。code
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) {
...
// do this last because it fires off messages to start doing things
try {
root.setView(view, wparams, panelParentView); // ViewRootImpl的setView 方法
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
synchronized (mLock) {
final int index = findViewLocked(view, false);
if (index >= 0) {
removeViewLocked(index, true);
}
}
throw e;
}
}
复制代码
ViewRootImpl 的setView
方法是如何实现界面的更新的呢?orm
setView
方法中会调用 requestLayout()
方法去完成异步刷新请求:接口
@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
private static final String TAG = "ViewRootImpl";
...
// 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();
}
复制代码
咱们再查看 requestLayout
方法的源码,看它干了什么:
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals(); // scheduleTraversals 方法是View绘制的入口
}
}
复制代码
能够看到,是调用了 scheduleTraversals
方法进行绘制,scheduleTraversals
方法最终会调用 performTraversals
方法,咱们知道 performTraversals
是 View 执行绘制过程的入口方法,该方法会通过测量、布局、绘制这三个过程把 View 绘制出来。
View 绘制出来之后是怎么经过IPC调用的方式添加到 Window 中的呢?
咱们知道,WindowManager 是外界访问 Window 的入口,因此最终 WindowManager 会经过 IPC 的方式调用 WindowManagerService 的 addWindow
方法,这样一来, Window 的添加请求就交给了 WindowManagerService 来处理了,而后 WindowManagerService 会通过一系列的操做将 View 添加到 Window 中并展现出来。
做为应用层开发者来讲,了解到这个程度我的以为就能够了,不必去深究 WindowManagerService 的实现细节,至于 WindowManagerService 是如何处理 Window 的添加请求的,感兴趣的读者能够去查看源码。
参考书籍:《Android 开发艺术探索》