View的绘制流程

首先从Activity#setContentView(layoutResID)–>PhoneWindow#setContentView(layoutResID)–>然后执行 installDecor(), mLayoutInflater.inflate(layoutResID, mContentParent),
在installDecor()中会执行,generateDecor()实例化Decor, mContentParent=generateLayout(mDecor)给mContentParent赋值,根据不同的主题,获取不同的布局,比如布局screen_simple.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical">
    <ViewStub android:id="@+id/action_mode_bar_stub"
              android:inflatedId="@+id/action_mode_bar"
              android:layout="@layout/action_mode_bar"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:theme="?attr/actionBarTheme" />
    <FrameLayout
         android:id="@android:id/content"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:foregroundInsidePadding="false"
         android:foregroundGravity="fill_horizontal|top"
         android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>

获取到布局之后

mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);

将该布局添加到mDecor中
之后

ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);

将布局中的FrameLayout赋给contentParent,故
mLayoutInflater.inflate(layoutResID, mContentParent)将 layoutResId的布局添加到mContentparent中,即在Activity#setContentView(layoutResID),最后其实是将布局添加到了DecorView的id为content的FrameLayout中

然后开始View的绘制:
在ActivityThread中类H继承自Handler, 在其handleMessage中,收到LAUNCH_ACTIVITY 的指令后,开始执行handleLaunchActivity()–>handleResumeActivity()–>WindowManagerImpl#addView(decor, l)–>WindowManagerGlobal#addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) -->ViewRootImpl#setView(view, wparams, panelParentView)将decorview和ViewRootImpl进行关联

绘制的类及方法:
ViewRootImpl#setView(view, wparams, panelParentView)–>requestLayout()

@Override
public void requestLayout() {
    if (!mHandlingLayoutInLayoutRequest) {
        checkThread();
        mLayoutRequested = true;
        scheduleTraversals();
    }
}

先检查是否在主线程,不在就抛异常,在就执行scheduleTraversals()

void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        mChoreographer.postCallback(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        if (!mUnbufferedInputDispatch) {
            scheduleConsumeBatchedInput();
        }
        notifyRendererOfFramePending();
        pokeDrawLockIfNeeded();
    }
}

mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);的参数mTraversalRunnable是一个线程,其中执行了 doTraversal()方法

final class TraversalRunnable implements Runnable {
    @Override
    public void run() {
        doTraversal();
    }
}

doTraversal中执行performTraversals(),在performTraversals()中开启绘制的三大步骤:

测量:ViewRootImpl#performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);-->mView.measure()
布局:ViewRootImpl#performLayout(lp, mWidth, mHeight);-->host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
绘制:ViewRootImpl#performDraw();-->draw(fullRedrawNeeded)-->drawSoftware-->mView.draw(canvas);

performMeasure中的参数

int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);

让我们看看getRootMeasureSpec方法

private static int getRootMeasureSpec(int windowSize, int rootDimension) {
    int measureSpec;
    switch (rootDimension) {

    case ViewGroup.LayoutParams.MATCH_PARENT:
        // Window can't resize. Force root view to be windowSize.
        measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
        break;
    case ViewGroup.LayoutParams.WRAP_CONTENT:
        // Window can resize. Set max size for root view.
        measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
        break;
    default:
        // Window wants to be an exact size. Force root view to be that size.
        measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
        break;
    }
    return measureSpec;
}

根据窗口大小和子View的LayoutParams来确定子View的MeasureSpec .接着执行mView.measure(),会跳转到View的measure方法,接着会执行onMeasure,因为DecorView继承自FrameLayout,所以会执行FrameLayout#onMeasure,

    for (int i = 0; i < count; i++) {
        final View child = getChildAt(i);
        if (mMeasureAllChildren || child.getVisibility() != GONE) {
            measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
            maxWidth = Math.max(maxWidth,
                    child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
            maxHeight = Math.max(maxHeight,
                    child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
            childState = combineMeasuredStates(childState, child.getMeasuredState());
            if (measureMatchParentChildren) {
                if (lp.width == LayoutParams.MATCH_PARENT ||
                        lp.height == LayoutParams.MATCH_PARENT) {
                    mMatchParentChildren.add(child);
                }
            }
        }
    }
    ……
 setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
                resolveSizeAndState(maxHeight, heightMeasureSpec,
                        childState << MEASURED_HEIGHT_STATE_SHIFT));

先调用measureChildWithMargins 循环测量子View的大小,最后设置自身的大小。再看看measureChildWithMargins的实现

protected void measureChildWithMargins(View child,
        int parentWidthMeasureSpec, int widthUsed,
        int parentHeightMeasureSpec, int heightUsed) {
    final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

    final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
            mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
                    + widthUsed, lp.width);
    final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
            mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
                    + heightUsed, lp.height);

    child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}

getChildMeasureSpec的规则如下图所示
在这里插入图片描述
先获取子View的MeasureSpec,然后调用子View的child.measure(childWidthMeasureSpec, childHeightMeasureSpec);这样绘制就从父容器传递到了子容器。
再看看View的onMeasure的实现

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
            getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}

setMeasuredDimension:

protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
    boolean optical = isLayoutModeOptical(this);
    if (optical != isLayoutModeOptical(mParent)) {
        Insets insets = getOpticalInsets();
        int opticalWidth  = insets.left + insets.right;
        int opticalHeight = insets.top  + insets.bottom;

        measuredWidth  += optical ? opticalWidth  : -opticalWidth;
        measuredHeight += optical ? opticalHeight : -opticalHeight;
    }
    setMeasuredDimensionRaw(measuredWidth, measuredHeight);
}

setMeasuredDimensionRaw:

private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) {
    mMeasuredWidth = measuredWidth;
    mMeasuredHeight = measuredHeight;

    mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
}

最后只是给mMeasureWidth,mMeasureHeight赋值

汇总一下整个过程:
ViewRootImpl#setView()–>ViewRootImpl#requestLayout()–>scheduleTraversals()–>doTraversal()–>performTraversals–>ViewRootImpl#performMeasure#FrameLayout#measure(), measure中会调用onMeasure,onMeasure会对每个子View进行measure()过程,然后设置自己的测量大小。View的measure不用测量子View,直接设置自身的大小。

而layout过程与此类似:
mView.layout()–>FrameLayout#layout()–>FrameLayout#setFrame(),onLayout()–>FrameLayout#layoutChildren–>child.layout()–>View#layout(),View的layou会设置自身边界,其onLayout是个空实现。

draw过程:
mView.draw()–>View#draw

     *      1. Draw the background
     *      2. If necessary, save the canvas' layers to prepare for fading
     *      3. Draw view's content
     *      4. Draw children
     *      5. If necessary, draw the fading edges and restore layers
     *      6. Draw decorations (scrollbars for instance)

View#dispatchDraw()–>ViewGroup#dispatchDraw()–>ViewGroup#drawChild()–>child.draw() ,至此绘制也传到了子容器。
我也很蒙蔽

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值