View的繪製流程分析之二-Android對Window對象的管理機制分析

關於Window對象管理的相關類:


  • ViewManager

  • WindowManager

  • WindowManagerImpl

  • WindowManagerGlobal

  • ViewParent

  • ViewRootImpl

  • ActvityThread

  • WindowManagerService


Window是一個抽象類,具體實現類就是 PhoneWindow !

一個Window是通過一個View來承載的,還對應一個ViewRootImpl!

訪問Window必須通過WindowManager來實現!

Window具體操作方法實現實在WindowManagerImpl類中,方法定義在ViewManager接口中!

public interface ViewManager
{    
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

ViewManager接口定義了三個函數,分別對應window的添加,更新和刪除!

這裏寫圖片描述


addView

 @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
  • 1
  • 2
  • 3
  • 4
  • 5

其實WindowManagerImpl也沒有做具體的操作,而是交給了 WindowManagerGlobal

在WindowManagerImpl類中進行了初始化

private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
  • 1

WindowManagerGlobal.java

private WindowManagerGlobal() {
    }

    public static WindowManagerGlobal getInstance() {
        synchronized (WindowManagerGlobal.class) {
            if (sDefaultWindowManager == null) {
                sDefaultWindowManager = new WindowManagerGlobal();
            }
            return sDefaultWindowManager;
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

很明顯看出這是個單例模式


private final ArrayList<View> mViews = new ArrayList<View>();
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
private final ArrayList<WindowManager.LayoutParams> mParams =
            new ArrayList<WindowManager.LayoutParams>();
private final ArraySet<View> mDyingViews = new ArraySet<View>();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

WindowManagerGlobal中有四個重要的集合!

  • mViews集合存儲了所有window對應的View對象!

  • mRoots集合存儲了所有window對應的ViewRootImpl對象

  • mParams集合存儲了所有window對應的佈局參數

  • mDyingViews集合存儲了所有正在被刪除的window對象


public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        // 1. 驗證參數!
        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)) {
            throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
        }

        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        if (parentWindow != null) {
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        } else {
            final Context context = view.getContext();
            if (context != null
                    && (context.getApplicationInfo().flags
                            & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
                wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
            }
        }

        ViewRootImpl root; // 一個ViewRootImpl對象
        View panelParentView = null; // 一個View對象

        synchronized (mLock) {
            // ...
            // 查找view對應的index
            int index = findViewLocked(view, false);
            if (index >= 0) {
                if (mDyingViews.contains(view)) {// 如果正在被刪除的集合包含該view,則執行ViewRootImpl.doDie()函數
                    mRoots.get(index).doDie();
                } else {
                    throw new IllegalStateException("View " + view
                            + " has already been added to the window manager.");
                }
           }

            // ... 

            // 創建ViewRootImpl對象
            root = new ViewRootImpl(view.getContext(), display);
            // 設置佈局參數
            view.setLayoutParams(wparams);

            // 添加view到集合中
            mViews.add(view);
            // 添加ViewRootImpl到集合中
            mRoots.add(root);
            // 添加wparams參數到集合中
            mParams.add(wparams);
        }

        try {
            // 將view設置到ViewRootImpl中!
            root.setView(view, wparams, panelParentView);
        } catch (RuntimeException e) {
            // 設置異常則移除view
            synchronized (mLock) {
                final int index = findViewLocked(view, false);
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
            }
            throw e;
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70

函數最後通過ViewRootImpl.setView() 來完成window的添加過程!

在setView()內部調用了requestLayout()開啓了繪製流程!

View的繪製流程是由ViewRootImpl來完成的!

requestLayout(); 完成繪製流程之後,通過WindowSession來完成Window的添加過程!

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
            // ...

            try {
                    mOrigWindowType = mWindowAttributes.type;
                    mAttachInfo.mRecomputeGlobalAttributes = true;
                    collectViewAttributes();
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
                } catch (RemoteException e) {
                    mAdded = false;
                    mView = null;
                    mAttachInfo.mRootView = null;
                    mInputChannel = null;
                    mFallbackEventHandler.setView(null);
                    unscheduleTraversals();
                    setAccessibilityFocus(null, null);
                    throw new RuntimeException("Adding window failed", e);
                } finally {
                    if (restore) {
                        attrs.restore();
                    }
                }

            // ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

mWindowSession是IWindowSession類型變量,它是一個Binder對象!

真正的實現者是 Session

@Override
    public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
            Rect outOutsets, InputChannel outInputChannel) {
        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
                outContentInsets, outStableInsets, outOutsets, outInputChannel);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

這裏又通過WindowManagerService來實現window的添加,這樣window的添加事務就交給了WMS進行處理!


updateViewLayout

WindowMangerImpl.java

@Override
    public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.updateViewLayout(view, params);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
        // ...
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
        // 設置新的佈局參數
        view.setLayoutParams(wparams); 

        synchronized (mLock) {
            int index = findViewLocked(view, true);
            ViewRootImpl root = mRoots.get(index);
            mParams.remove(index);
            mParams.add(index, wparams); // 更新mParams集合對應的值
            root.setLayoutParams(wparams, false); // 更新ViewRootImpl中的參數, false表示不是一個新的view
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

ViewRooImpl.java

void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
        synchronized (this) {
            // ...

            if (newView) {
                mSoftInputMode = attrs.softInputMode;
                requestLayout();
            }

            //...

            mWindowAttributesChanged = true;
            scheduleTraversals();
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在這個函數裏面又調用了scheduleTraversals() 來重新進行測量,佈局,繪製流程!


removeView

在ViewManager接口中只有一種刪除函數:

public void removeView(View view);
  • 1

但是在WindowManager接口中又增加了一種刪除view的方式:

public void removeViewImmediate(View view); // 立即刪除
  • 1

這兩種方式,一種表示同步刪除,一種表示異步刪除

但是兩者都會去調用 WindowManagerGlobal中的 removeView() 函數!

WindowManagerImpl.java

@Override
    public void removeView(View view) {
        mGlobal.removeView(view, false);
    }
  • 1
  • 2
  • 3
  • 4
@Override
    public void removeViewImmediate(View view) {
        mGlobal.removeView(view, true);
    }
  • 1
  • 2
  • 3
  • 4

WindowManagerGlobal.java

public void removeView(View view, boolean immediate) {
        if (view == null) {
            throw new IllegalArgumentException("view must not be null");
        }

        synchronized (mLock) {
            // 查找要被刪除view的索引
            int index = findViewLocked(view, true);
            // 從mRoots這個集合中得到view對象
            View curView = mRoots.get(index).getView();
            // 執行刪除操作
            removeViewLocked(index, immediate);
            if (curView == view) {
                return;
            }

            throw new IllegalStateException("Calling with view " + view
                    + " but the ViewAncestor is attached to " + curView);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

removeView() 第二個參數表示是否立刻刪除~

private void removeViewLocked(int index, boolean immediate) {
        // 獲取view對應的ViewRootImpl對象
        ViewRootImpl root = mRoots.get(index);
        View view = root.getView();

        // ...
        // 調用View中的die()函數
        boolean deferred = root.die(immediate);
        if (view != null) {
            view.assignParent(null);
            if (deferred) { // 添加到正在被刪除的集合中
                mDyingViews.add(view);
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

ViewRootImpl.java

boolean die(boolean immediate) {
        // 立刻刪除時,直接執行doDie()函數完成真正的刪除操作!然後返回false
        if (immediate && !mIsInTraversal) {
            doDie();
            return false;
        }

        // ...
        // 異步刪除時,發送一個請求刪除的消息,然後直接返回true
        mHandler.sendEmptyMessage(MSG_DIE);
        return true;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

其實在異步刪除時,handler處理的時候也是調用的doDie()函數來完成刪除!

case MSG_DIE:
   doDie();
   break;
  • 1
  • 2
  • 3

ViewRootImpl.java

void doDie() {
        checkThread(); // 檢查線程, 很多地方都會調用這個函數!

        synchronized (this) {
            if (mRemoved) { // mRemoved默認是false,doDie()函數執行時變爲true
                return;
            }
            mRemoved = true;
            if (mAdded) { // 如果當前window對象應被添加到屏幕上!則需要回調detach函數
                dispatchDetachedFromWindow();
            }

            if (mAdded && !mFirst) {
                destroyHardwareRenderer(); // 停止硬件渲染

                if (mView != null) {
                    int viewVisibility = mView.getVisibility();
                    boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
                    if (mWindowAttributesChanged || viewVisibilityChanged) { // 如果window屬性更改或者顯示方式改變

                        try {
                            if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
                                    & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
                                mWindowSession.finishDrawing(mWindow);
                            }
                        } catch (RemoteException e) {
                        }
                    }

                    mSurface.release(); // 釋放資源
                }
            }

            mAdded = false; // 狀態還原
        }
        WindowManagerGlobal.getInstance().doRemoveView(this);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

WindowManagerGlobal.java

void doRemoveView(ViewRootImpl root) {
        synchronized (mLock) {
            final int index = mRoots.indexOf(root); 
            if (index >= 0) {
                mRoots.remove(index);// 從ViewRootImpl集合中刪除
                mParams.remove(index); //  刪除對應的參數
                final View view = mViews.remove(index); // 刪除對應的view
                mDyingViews.remove(view);// 從正在被刪除的集合中刪除view
            }
        }
        if (ThreadedRenderer.sTrimForeground && ThreadedRenderer.isAvailable()) {
            doTrimForeground();
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

再來看看dispatchDetachedFromWindow()函數

void dispatchDetachedFromWindow() {
        if (mView != null && mView.mAttachInfo != null) {
            mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
            mView.dispatchDetachedFromWindow(); // 回調view的detach函數!方法內部會調用onDetachedFromWidow()函數 和 onDetachedFromWindowInternal()函數
        }

        // ...

        destroyHardwareRenderer();

        // ...

        mSurface.release();

        // ...
        try {
            mWindowSession.remove(mWindow);
        } catch (RemoteException e) {
        }

        // ...

        mDisplayManager.unregisterDisplayListener(mDisplayListener);

        unscheduleTraversals();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

再次通過IPC方式調用remove()函數!

Session.java

public void remove(IWindow window) {
        mService.removeWindow(this, window);
    }
  • 1
  • 2
  • 3

WMS.java

public void removeWindow(Session session, IWindow client) {
        synchronized(mWindowMap) {
            WindowState win = windowForClientLocked(session, client, false);
            if (win == null) {
                return;
            }
            removeWindowLocked(win);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
void removeWindowLocked(WindowState win) {
        removeWindowLocked(win, false);
    }
  • 1
  • 2
  • 3
void removeWindowLocked(WindowState win, boolean keepVisibleDeadWindow) {
        win.mWindowRemovalAllowed = true;
        // ...

        boolean wasVisible = false;
        // ...

        removeWindowInnerLocked(win);
        // ...
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

removeWindowInnerLocked(win); 方法內部分析先暫停!!!

http://blog.csdn.net/crazy1235/article/details/72633389

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