近来一段时间,忙于对app架构的理解,脑袋里的浆糊也慢慢泡开了,终于有时间着手了解一个android最重要的2个View的渲染过程(View和ViewGroup)

分析:

第一部分(测量,measure)

1. 在View的源码里面有3个方法

public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 
.......
onMeasure(widthMeasureSpec, heightMeasureSpec);
........
  }
 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
      setMeasuredDimension(
getDefaultSize(getSuggestedMinimumWidth(),widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(),heightMeasureSpec)
);
     }
protected final void setMeasuredDimension(int measuredWidth, int  measuredHeight) {
 
}

根据上面3个方法可以看出三个方法的调用过程

------->Measure------->onMeasure

------->setMeasuredDimension

2.ViewGroup里面未重写 上面3个方法,而在ViewGroup的子类里面

FrameLayout. onMeasure里面有{
child.measure(childWidthMeasureSpec,  childHeightMeasureSpec);
}
LinearLayout,onMeasure里面有{
 measureChildBeforeLayout(
        child, i, widthMeasureSpec, 0, heightMeasureSpec,
      otalWeight == 0 ? mTotalLength : 0);
}
 
GridLayout. onMeasure里面有{
   measureChildrenWithMargins(widthSpecSansPadding,
heightSpecSansPadding, true);
}
 
RelativeLayout. onMeasure里面有{
measureChild(child, params, myWidth, myHeight);
}
ViewPager  onMeasure里面有{
child.measure(widthSpec, mChildHeightMeasureSpec);
}

不管以为什么方式 onMeasure里面都会调用到child.measure

 

所以看出来ViewGroup是呈递归测量的

Measure->(onMeasure->child.measure)(递归)

->setMeasuredDimension

3. 而在View里面的非ViewGroup子类中,

如:ImageView,TextView中

虽然复写了onMeasure方法,但是最后还是会调用setMeasuredDimension

 

是不是有点晕? 没事有图


android 提升VLC线程渲染 android view渲染机制_android 提升VLC线程渲染

 

 

第二部分(布局,layouy)


1. 在View的源码里面有这样2个方法

protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
 
}
 public void layout(int l, int t, int r, int b){
onLayout(boolean changed, int left, int top, int right, int bottom) 
}

2. 可以看出 layout会调用 onLayout


3. 在ViewGroup中,onLayout变成了抽象方法,所以ViewGroup的子类都要去实现    它

protected abstract void onLayout(boolean changed,
int l, int t, int r, int b);

而最后跟进源码发现,ViewGroup的非抽象子类中都复写onLayout的时候都间接直接的调用了child.layout


FrameLayout. onLayout{
  child.layout(childLeft, childTop, childLeft + width, childTop +  height);
}
 
 
GridLayout. onLayout{
c.layout(cx, cy, cx + width, cy + height);
}
 
 
LinearLayout. onLayout{
protected void onLayout(boolean changed, int l, int t, int r, int b) {
         if (mOrientation == VERTICAL) {
            layoutVertical(l, t, r, b);
        } else {
            layoutHorizontal(l, t, r, b);
        }
}
}
 
RelativeLayout onLayout{
for(){
   child.layout(st.mLeft, st.mTop, st.mRight, st.mBottom);
}
}

所以看出来ViewGroup是逐级布局的

是不是有点晕? 没事有图


android 提升VLC线程渲染 android view渲染机制_子类_02

 

 

为什么这里不是递归的呢View的源码

 

public static boolean isLayoutModeOptical(Object o) {
        return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical();
    }
 
public void layout(int l, int t, int r, int b) {
        int oldL = mLeft;
        int oldT = mTop;
        int oldB = mBottom;
        int oldR = mRight;
//第一步,先判断是不是ViewGroup类型,
// ---不是的话(非ViewGroup的View子类)判断是否有变化并且设值
// 是的话(ViewGroup)也判断是否有变化并且设值
//第二步,观察该对象是否有变化,如果变化进入if
        boolean changed = isLayoutModeOptical(mParent) ?
                setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
        if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
//第三步调用onLayout(只有在viewGroup的子类中才会重写)
            onLayout(changed, l, t, r, b);
            mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;
 
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnLayoutChangeListeners != null) {
                ArrayList<OnLayoutChangeListener> listenersCopy =
                        (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone();
                int numListeners = listenersCopy.size();
                for (int i = 0; i < numListeners; ++i) {
                    listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB);
                }
            }
        }
        mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;
    }

 

第三部分(渲染,ondraw)


1. 在View的源码里面有这样2个方法

protected void onDraw(Canvas canvas) {
    }
public void draw(Canvas canvas) {
onDraw(Canvas canvas) ;
}

2. 可以看出 draw会调用 onDraw


3. 在ViewGroup的子类中,并未复写这2个方法,而ViewGroup的有的子类复写

onDraw而有的没有 即使复写了也没draw子控件,但是ViewGroup 有个方法

protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
         return child.draw(canvas, this, drawingTime);
}

 drawChild 会在dispatchDraw 中被调用 让我们来看看dispatchDraw 方法 是啥玩意?

在View的方法注释上有这么一段话

Called by draw to draw the child views. This may be overridden

by derived classes to gain control just before its children are drawn

(but after its own view has been drawn).

当这个方法调用的时候,就会渲染子控件,当时必须在控件渲染之后

 

当我寻遍了View的子类 发现毫无dispatchDraw 迹象,然后我在View的draw的方法里面发现调用了View的dispatchDraw..........

其实onDraw执行判断玩后应该是dispatchDraw(Canvas canvas) 然后在ViewGroup里面实现了dispatchDraw(Canvas canvas),并且让方法里面去添加drawChildren

View的非ViewGroup里面dispatchDraw(Canvas canvas)是空实现。

那么我就重写画个图

 


android 提升VLC线程渲染 android view渲染机制_子类_03

 

 

后记:

虽然现在只能用用大神们的框架,很多人会觉得做这么多事情是多余的,当时我觉得但是分析控件的渲染过程还是有好处的,毕竟我们要去了解这些懂得的处理过程,然后去才能更好的去理解大神的框架,也许有一天,我们也能更好的维护出自己的小玩意,过段日子,准备看些源码,总结一下事件的传递机制。