1. 程式人生 > >android的視窗機制分析------ViewRoot類

android的視窗機制分析------ViewRoot類

    ViewRoot是GUI管理系統與GUI呈現系統之間的橋樑,根據ViewRoot的定義,我們發現它並不是一個View型別,而是一個Handler。

它的主要作用如下:

A. 向DecorView分發收到的使用者發起的event事件,如按鍵,觸屏,軌跡球等事件;

B. 與WindowManagerService互動,完成整個Activity的GUI的繪製。

    事件處理和GUI繪製的具體實現在後面的文章中再描述,這篇文章就主要介紹ViewRoot物件如何同WindowManagerService橋接起來的。    

    在完成Activity的ContentView設定之後,下面的工作就是準備顯示了,準備顯示的主要工作就是建立起Application和WindowManagerService之間的聯絡,第一步的工作就是向WindowManager新增前面涉及到的DecorView,我們已經知道這個DecorView包含了整個Activity的GUI,所以我們只需要把這個DecorView交給WindowManager打理就可以了。

    下面看看整個的過程    

A.     向WindowManager新增DecorView;


                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;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (a.mVisibleFromClient) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
                }

B. WindowManagerImpl儲存DecorView到mViews,建立對應的ViewRoot;

C.呼叫ViewRootsetView()方法


這個方法中的主要工作就是建立起與WindowManagerService之間的聯絡。
                requestLayout();
                try {
                    res = sWindowSession.add(mWindow, mWindowAttributes,
                            getHostVisibility(), mAttachInfo.mContentInsets);
                } catch (RemoteException e) {

在這個方法中只需要關注兩個步驟

(1)   requestLayout()

    請求WindowManagerService繪製GUI,但是注意一點的是它是在與WindowManagerService建立連線之前繪製,為什麼要在建立之前請求繪製呢?

    其實兩者實際的先後順序是正好相反的,與WMS建立連線在前,繪製GUI在後,那麼為什麼程式碼的順序和執行的順序不同呢?這裡就涉及到ViewRoot的屬性了,我們前面提到ViewRoot並不是一個View,而是一個Handler,那麼執行的具體流程就是這樣的:

a)       ActivityThread的handler函式註冊了啟動一個新的Activity的請求處理LAUNCH_ACTIVITY,LAUNCH_ACTIVITY的處理過程呼叫到了ViewRoot的setView()方法,因此上圖程式碼在被執行時正處於LAUNCH_ACTIVITY訊息的處理過程中。

b)       requestLayout()其實是向messagequeue傳送了一個請求繪製GUI的訊息,並且ViewRoot和ActivityThread共用同一個MessageQueue(如下圖),因此繪製GUI的過程一定是在LAUNCH_ACTIVITY訊息被處理完之後,也就是sWindowSessoin.add()方法呼叫完之後。


(2)   sWindowSessoin.add()

從字面意思理解的話,IWindowSession sWindowSessoin是ViewRoot和WindowManagerService之間的一個會話層,它的實體是在WMS中定義,作為ViewRoot requests WMS的橋樑。

add()方法的第一個引數mWindow是ViewRoot提供給WMS,以便WMS反向通知ViewRoot的介面。由於ViewRoot處在application端,而WMS處在system_server程序,它們處在不同的程序間,因此需要新增這個IWindow介面便於GUI繪製狀態的同步。