1. 程式人生 > >android view requestLayout,invalidate 事件的分發,接收,以及處理

android view requestLayout,invalidate 事件的分發,接收,以及處理

handleResumeActivity

DecorView 是在ActivityThread 中的handleResumeActivity 通過mWindowManager 掛到 ViewRootImpl()上面去的。

所以所有的 view 的 requestLayout(),invalidate(),

都是通過 自身的parent.invalidate(),一步一步傳遞到最頂層的 DecorView,然後最後傳遞到ViewRootImpl裡面。

這個事App process中的windowmanager中的一個成員變數

猜測應該是 每個acitivity 或者dialog都是一個window 要註冊到這個裡面去。

WindowManagerImpl 也變成了本地的代理。

在WindowManagerGlobal中 維護了這樣一個 rootview 視窗的佇列
private final ArrayList mViews = new ArrayList();
時刻保證 哪個視窗在最前面,點選事件傳給誰。

他通過 openSession(),將自己和遠端service繫結起來

WindowManagerGlobal 中


    public void addView(View view, ViewGroup.LayoutParams params,

。。。。。

//rootImpl
            root.setView
(view, wparams, panelParentView); 。。。。 }

ViewRootImpl.java

public void setView()

//通過rootImpl                     res = //mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets
, mAttachInfo.mStableInsets, mInputChannel);

這樣子直接掛到了 windowmanagerService 上面註冊,準備接受事件用,
什麼touch事件啊 之類的都是通過windowmanagersetvice 中持有這個window的token 進行下發的。

扯遠了 繼續看 requestLayout();

在ViewRootImpl 中,

   @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }
    void invalidate() {
        mDirty.set(0, 0, mWidth, mHeight);
        if (!mWillDrawSoon) {
            scheduleTraversals();
        }
    }

可以看到 不管是request 還是invalidate 都會 呼叫相同的程式碼scheduleTraversals();我們可以這麼理解,就是說 layout和重繪都是在一次繪製過程中完成的,而不是兩次。

在簡單點描述就是 你在程式碼裡面 前面請求requestLayout(),並且也請求了invalidate(),並不會產生兩次 重繪。

在簡單點來說,在一個msg迴圈裡面,你多次請求requestLayout(),都是會被系統合併的。

    void scheduleTraversals() {
//如果已經在 重繪的過程中,這個請求會被忽略掉的。
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
//這個東西很厲害的,在messageQuene中會設定柵欄,涉及到垂直同步的問題。
            mTraversalBarrier = mHandler.getLooper().postSyncBarrier();

//在mChoreographer會發出一個sync 的訊號。
//並且在下個訊息迴圈的時候 做doTraversal(),準備開始重新layout
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
            notifyRendererOfFramePending();
        }
    }

它會在整個訊息迴圈中加設一個柵欄,在接觸此柵欄之前,後面的訊息絕對不可能執行,其實就是為了,騰出cpu來 做layout draw事件

    int enqueueSyncBarrier(long when) {
    }