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 開發藝術探索》