015.ViewRoot和DecorView

来源:互联网 发布:黑苹果安装ubuntu 编辑:程序博客网 时间:2024/04/30 12:37
    学习工作原理的话,首先要知道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.

    
        
0 0