Window 的新增過程
Window 的新增過程
Window(或者說View) 是怎麼新增到 Android 系統中然後展示給使用者的?讓我們來探索一下 Window 的新增過程。
Window 新增過程的入口方法
要探索新增的過程,必須先在原始碼中找到新增 Window 的入口方法。
Window 的新增需要通過 WindowManager 的addView
方法實現,但 WindowManager 是個介面,它的真正實現類是 WindowManagerImpl 類,但 WindowManagerImpl 也並沒有直接實現對 Window 的新增、刪除、更新操作,而是通過橋接模式將所有操作委託給 WindowManagerGlobal 去實現。最終會呼叫 WindowManagerGlobal 類的addView
方法真正開啟 View 的新增過程。
所有,Window 新增過程的真正入口方法實際上是 WindowManagerGlobal 類的addView
方法。
Window 新增過程的主要流程
WindowManagerGlobal 的addView
方法主要分為三大步:
-
檢查引數 params 是否是 WindowManager.LayoutParams,如果不是說明引數不合法,則會丟擲異常。
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 新增到列表中。
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 的新增過程。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
方法是如何實現介面的更新的呢?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
是 View 執行繪製過程的入口方法,該方法會經過測量、佈局、繪製這三個過程把 View 繪製出來。 -
View 繪製出來以後是怎麼通過IPC呼叫的方式新增到 Window 中的呢?
我們知道,WindowManager 是外界訪問 Window 的入口,所以最終 WindowManager 會通過 IPC 的方式呼叫 WindowManagerService 的
addWindow
方法,這樣一來, Window 的新增請求就交給了 WindowManagerService 來處理了,然後 WindowManagerService 會經過一系列的操作將 View 新增到 Window 中並展示出來。作為應用層開發者來說,瞭解到這個程度就差不多了,沒必要去深究 WindowManagerService 的實現細節,至於 WindowManagerService 是如何處理 Window 的新增請求的,感興趣的讀者可以去檢視原始碼。
-
參考書籍:
《Android 開發藝術探索》