WindowManagerImpl,WMG與WMS入門

基礎

        每一個Activity(包括dialog)都有一個Window對象,而它們顯示的佈局又是添加到該Window對象中的mDecor中的。而mDecor又是通過WindowManager#addView()才展示出來的。這一點可查看AlertDialog,或者是見ActivityThread中的一部分代碼,如下:

            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();
                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);
                }
            }

        這一段代碼會在startActivity()時調用,它截自ActivityThread#handleResumeActivity()。

        從上面也可看出,它和AlertDialog的處理方式完全一樣,直接使用WindowManager#addView(decor,1);。因此,可以知道,要想展示某個View到Window上,必須通過WindowManager#addView()進行。也就是說WindowManager是View展示的橋樑。

        WindowManager是接口,通過getSystemService()可知它的具體實現類爲WindowManagerImpl。而對於後者,有一成員變量mGlobal指向的是一個WindowManagerGlobal實例,其內部完全是使用WindowManagerGlobal進行操作。

構造函數

        Activity#attach()->Window#setWindowManager()->WindowManagerImpl#createLocalWindowManager(this)->WindowManagerImpl#構造函數,在構造函數中爲mParentWindow成員變量賦值。

        因此,WindowManagerImpl通過mParentWindow指向Window——這個Window對象也是Activity中mWindow指向的Window實例,而Window通過mWindowManager指向WindowManagerImpl實例。

WindowManagerGlobal

        單例。其內部有三個變量如下:

    private final ArrayList<View> mViews = new ArrayList<View>();//存儲所有addView時的view的
    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();//存儲所有的ViewRootImpl的
    private final ArrayList<WindowManager.LayoutParams> mParams =
            new ArrayList<WindowManager.LayoutParams>();//view對應的LayoutParams,是WindowManager.LayoutParams
有一點要注意:同一index下,它們三個對應的元素是對應的。

addView

代碼如下:

public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        //略。對view,display的非空判斷。且要求params必須是WindowManager.LayoutParams
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        //略
        ViewRootImpl root;
        View panelParentView = null;
        synchronized (mLock) {
            //略
            //爲view設置LayoutParams,並存儲
            root = new ViewRootImpl(view.getContext(), display);
            view.setLayoutParams(wparams);
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
        }
        try {
            root.setView(view, wparams, panelParentView);
        } //略
    }

        邏輯很簡單,內容new一個ViewRootImpl,並調用其setView()方法。

getWindowSession

    public static IWindowManager getWindowManagerService() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowManagerService == null) {
                sWindowManagerService = IWindowManager.Stub.asInterface(
                        ServiceManager.getService("window"));
                try {
                    sWindowManagerService = getWindowManagerService();
                    ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());
                } catch (RemoteException e) {
                    Log.e(TAG, "Failed to get WindowManagerService, cannot set animator scale", e);
                }
            }
            return sWindowManagerService;
        }
    }

    public static IWindowSession getWindowSession() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowSession == null) {
                try {
                    InputMethodManager imm = InputMethodManager.getInstance();
                    IWindowManager windowManager = getWindowManagerService();
                    sWindowSession = windowManager.openSession(
                            new IWindowSessionCallback.Stub() {
                                @Override
                                public void onAnimatorScaleChanged(float scale) {
                                    ValueAnimator.setDurationScale(scale);
                                }
                            },
                            imm.getClient(), imm.getInputContext());
                } catch (RemoteException e) {
                    Log.e(TAG, "Failed to open window session", e);
                }
            }
            return sWindowSession;
        }
    }

        首先通過getWindoeManagerService()拿到WMS在本進程中的代理對象。分兩步:1)通過ServiceManager#getService()拿到WMS在本地的IBinder對象;2)通過asInterface()爲IBinder對象創建一個代理類,本進程與WMS的交互就通過該代理類進行。

        在getWindowSession()中,通過代理類調用WMS中的openSession(),後者返回的是一個Session對象。所以getWindowSession()返回的是Session對象在本地的代理,而它的具體實例在WMS所屬的進程中。

        getWindowSession()拿到Session對象的代理類後,就可通過sWindowSession對象訪問Session實例中的方法。而Session中,一般的方法都是調用WMS實例完成的(兩者屬於同一進程,所以通過sWindowSession調用方法相當於間接地調用了WMS中的方法)。因此Session對象是本進程調用WMS的橋樑。

WindowManagerService

        addView()->ViewRootImpl#setView()->Session#addToDisplay()->WMS#addWindow()。從addView()到setView()前半部分(到requestLayout()截止),都是對addView()中的View參數進行操作。從setView到最後,卻是對Window的顯示進行操作。

addWindow

    public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            InputChannel outInputChannel) 

        第一個參數爲getWindowSession()方法返回值在WMS所在進程中的實例。

        第二個參數爲IWindow對象,由ViewRootImpl構造函數中創建,在ViewRootImpl#setView()中調用Session#addToDisplay()時將該對象當作參數傳遞進去,所以WMS進程會得到一個W的代理對象,進而WMS可以使用它調用應用進程中的方法。

        attrs爲WMG#addView()時View所使用的LayoutParams對象,是由應用進程傳遞到WMS進程中的。

        對於client,addWindow()中有如下代碼:

            WindowState win = new WindowState(this, session, client, token,
                    attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);

將client又賦值給WindowState#mClient,而WindowState又使用mClient調用應用進程中的方法。由此要知client的作用就是提供一個讓WMS調用應用進程中方法的橋樑。

        WMS進程由client調用用戶進程,而用戶進程通過Session對象調用WMS進程。












發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章