015.ViewRoot和DecorView

    學習工作原理的話,首先要知道View有三大流程,測量流程、佈局流程、繪製流程。之後再學習一些常見的回調方法,這樣在我們寫自定義View的時候,就能更加得心應手了。
    
1.ViewRoot:
    ViewRoot對應ViewRootImpl類,它連接着WindowManager和DecorView。View的三大流程,都是同個ViewRoot來實現的。在ActivityThread中,當Activity對象被創建以後,會把Decorview添加到Window中,並且會創建ViewRootImpl對象,同時將ViewRootImpl和DecorView關聯起來。
    ActivityThread中handleResumeActivity方法可以看到
    //表示剛創建的Activity
  if (r.window == null && !a.mFinished && willBeVisible) {
                //創建窗口,賦予Activity
                r.window = r.activity.getWindow();
               //獲取DecorView
                 View decor = r.window.getDecorView();
                //設置不可見
                decor.setVisibility(View.INVISIBLE);
                //獲取WindowManager
                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);
                }
            } 

    wm.addView( decor, l ) 是調用WindowManagerGlobal的addView方法,在WindowManagerGlobal的addView方法中,有如下代碼:

            ……………………
            root = new ViewRootImpl(view.getContext(), display);

            view.setLayoutParams(wparams);

            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
    }
     try {
                root.setView(view, wparams, panelParentView);
            } catch (RuntimeException e) {
                // BadTokenException or InvalidDisplayException, clean up.
                synchronized (mLock) {
                    final int index = findViewLocked(view, false);
                    if (index >= 0) {
                        removeViewLocked(index, true);
                    }
               }
                throw e;
            }
    View的繪製流程師從ViewRoot的performTraversals開始的。如上面,就是依次執行ViewRoot的setView->requestLayout->scheduleTraversals->scheduleTraversalRunnable#run->performTraversals方法。
    繪製出一個View,需要經過measure,layout和draw。

    在performTraversals中,會依次調用performMeasure、performLayout和performDraw三個方法,分別完成頂級View的measure、layout和draw三大流程。其中measure、layout和draw都和之前事件分發機制一樣,performMeasure->measure->onMeasure->子View measure->onMeasure ……流程就像事件傳遞一樣傳遞下去。如此反覆,就遍歷了整個View樹。
    
    measure過程決定了View的寬高,Measure完成了以後,可以通過getMeasureWidth和getMeasureHeight方法來獲取到View測量後的寬高,一般情況下,這時候得到的寬高就是View最終的寬高,但是,有特殊情況。Layout過程決定了最終View的四個訂單的座標和實際的寬高。可以通過getTop getBottom getLeft getRight 拿到View的四個頂點的位置,並且可以通過getWidth和getHeight拿到View最終的寬高。Draw的過程決定了View的顯示,只有draw方法完成以後view的內容才能顯示在屏幕上。

2.DecorView
    DecorView是我們Activity的頂級View,一般情況,DecorView包含着一個vertical的LinearLayout,上面是一個titlebar 下面是一個ViewGroup id就是android.R.id.content,所以我們Activity是setContentView
    同時,DecorView其實是一個FrameLayout,View層的事件都先經過DecorView,然後才傳遞給我們的View.

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