展开说说:Android页面绘制流程源码解析

说到Android系统View的绘制流程大家一定知道是分为测量(Measure)、布局(Layout)和绘制(Draw)三个阶段这篇文章主要聊一聊在这三个步骤之前的源码执行流程,页面启动后是怎样通过代码执行这三个方法

之前看过startActivity启动一个Activity最终都会经过ActivityThread类来调用Activity的生命周期。所以我们就从ActivityThread中调用onResume的performResumeActivity方法开始。

1、ActivityThread类的performResumeActivity方法

首先通过performResumeActivity调用Activity的onResume方法,之前在“四大组件”专栏中分析过这个方法。

final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);

继续向下看:

ViewManager wm = a.getWindowManager();

此处省略好多行。。。。

wm.addView(decor,l)

这里第一个参数就是DecorView的实例,执行顺序在performResumeActivity后面.

补充一下,此处的wm类型是ViewManager,ViewManager是个接口

/** Interface to let you add and remove child views to an Activity. To get an instance
  * of this class, call {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
  */
public interface ViewManager
{
    /**
     * Assign the passed LayoutParams to the passed View and add the view to the window.
     * <p>Throws {@link android.view.WindowManager.BadTokenException} for certain programming
     * errors, such as adding a second view to a window without removing the first view.
     * <p>Throws {@link android.view.WindowManager.InvalidDisplayException} if the window is on a
     * secondary {@link Display} and the specified display can't be found
     * (see {@link android.app.Presentation}).
     * @param view The view to be added to this window.
     * @param params The LayoutParams to assign to view.
     */
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

WindowManager接口继承ViewManager,顺着可以找到WindowManager的实现类WindowManagerImpl。

2、来到WindowManagerImpl

@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
            mContext.getUserId());
}

3、进入WindowManagerGlobal类

addView方法最底下:

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

view.setLayoutParams(wparams);

mViews.add(view);
mRoots.add(root);
mParams.add(wparams);

// do this last because it fires off messages to start doing things
try {
    root.setView(view, wparams, panelParentView, userId);
} catch (RuntimeException e) {
    // BadTokenException or InvalidDisplayException, clean up.
    if (index >= 0) {
        removeViewLocked(index, true);
    }
    throw e;
}

这里创建ViewRootImpl并且会调用ViewRootImpl的setView方法,这里传入的view就是上面wm.addView(decor,l)时传入的decorView他也会一直透传到ViewRootImpl的setView方法

4、ViewRootImpl的setView方法

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
        int userId) {
    synchronized (this) {
        if (mView == null) {
            mView = view;

下面省略好多行。。。。

上面的view就是从ActivityThread传递过来的DecorView实例,因此mView 就是DecorView,add方法下面滑油三个比较重要的点:requestLayout()mInputEventReceiver以及view.assignParent(this)

4.1 requestLayout调用scheduleTraversals

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

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

4.2 进入Choreographer类

上面mChoreographer.postCallBack, 这里会调用Choreographer类的postCallBack - postCallBackDelayed - postCallbackDelayedInternal - scheduleFrameLocked

@UnsupportedAppUsage
@TestApi
public void postCallback(int callbackType, Runnable action, Object token) {
    postCallbackDelayed(callbackType, action, token, 0);
}

@UnsupportedAppUsage
@TestApi
public void postCallbackDelayed(int callbackType,
        Runnable action, Object token, long delayMillis) {
    if (action == null) {
        throw new IllegalArgumentException("action must not be null");
    }
    if (callbackType < 0 || callbackType > CALLBACK_LAST) {
        throw new IllegalArgumentException("callbackType is invalid");
    }

    postCallbackDelayedInternal(callbackType, action, token, delayMillis);
}


private void postCallbackDelayedInternal(int callbackType,
        Object action, Object token, long delayMillis) {
    if (DEBUG_FRAMES) {
        Log.d(TAG, "PostCallback: type=" + callbackType
                + ", action=" + action + ", token=" + token
                + ", delayMillis=" + delayMillis);
    }

    synchronized (mLock) {
        final long now = SystemClock.uptimeMillis();
        final long dueTime = now + delayMillis;
        mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);

        if (dueTime <= now) {
            scheduleFrameLocked(now);
        } else {
            Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
            msg.arg1 = callbackType;
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, dueTime);
        }
    }
}


private void scheduleFrameLocked(long now) {
    if (!mFrameScheduled) {
        mFrameScheduled = true;
        if (USE_VSYNC) {
            if (DEBUG_FRAMES) {
                Log.d(TAG, "Scheduling next frame on vsync.");
            }

            // If running on the Looper thread, then schedule the vsync immediately,
            // otherwise post a message to schedule the vsync from the UI thread
            // as soon as possible.
            if (isRunningOnLooperThreadLocked()) {
                scheduleVsyncLocked();
            } else {
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
                msg.setAsynchronous(true);
                mHandler.sendMessageAtFrontOfQueue(msg);
            }
        } else {
            final long nextFrameTime = Math.max(
                    mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
            if (DEBUG_FRAMES) {
                Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
            }
            Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, nextFrameTime);
        }
    }
}

上面scheduleFrameLocked方法通过handler发了MSG_DO_FRAME的msg消息。

private final class FrameHandler extends Handler {
    public FrameHandler(Looper looper) {
        super(looper);
    }

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_DO_FRAME:
                doFrame(System.nanoTime(), 0);
                break;
            case MSG_DO_SCHEDULE_VSYNC:
                doScheduleVsync();
                break;
            case MSG_DO_SCHEDULE_CALLBACK:
                doScheduleCallback(msg.arg1);
                break;
        }
    }
}

 handleMessage中doFrame方法调用 doCallbacks,然后调用CallbackRecord

类的run方法 c.run(frameTimeNanos);

5、进入CallbackRecord

private static final class CallbackRecord {
    public CallbackRecord next;
    public long dueTime;
    public Object action; // Runnable or FrameCallback
    public Object token;

    @UnsupportedAppUsage
    public void run(long frameTimeNanos) {
        if (token == FRAME_CALLBACK_TOKEN) {
            ((FrameCallback)action).doFrame(frameTimeNanos);
        } else {
            ((Runnable)action).run();
        }
    }
}

通过((Runnable)action).run()看到是又回到了4.1中        mChoreographer.postCallback(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);可以看到是返回了ViewRootImpl的TraversalRunnable的实例mTraversalRunnable

6、返回ViewRootImpl 

((Runnable)action).run();  又调回到ViewRootImpl的TraversalRunnable的run方法调

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

 doTraversal方法调用performTraversals()方法

performTraversals()方法,measure测量、layout布局、draw绘制,都是在这个方法开启的
  预测量

windowSizeMayChange |= measureHierarchy(host, lp, res,
        desiredWindowWidth, desiredWindowHeight);

布局窗口
 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);

控件树测量

 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec)

布局控件
 performLayout(lp,mWidth,mHeight)  

绘制控件
 performDraw()

以measure控件树测量为例看看怎样调用到View的measure方法:

private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
    if (mView == null) {
        return;
    }
    Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
    try {
        mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    }
}

但是DecorView类没有measure(int widthMeasureSpec, int heightMeasureSpec)方法,因此执行顶级父类View的measure方法:

onMeasure(widthMeasureSpec, heightMeasureSpec);

View的measure方法会调用onMeasure,DecorView中有此方法因此来到DecorView:

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

这里super又会调用父类FrameLayout中的onMeasure方法,方法很长只截取部分:

FrameLayout根据它的MeasureSpec调用measureChildWithMargin方法来对每一个子View进行测量

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);
            }
        }
    }
}

DecorView委托父类对所有子view完成测量。

7、ViewRootImpl的setView方法

再说剩下的两个重要的点,后面再细致的单独分析:
     res=mWindowSession.addToDisplayAsUser(),与requestLayout同在setView方法,负责将窗口添加到WMS上,主要通过mWindowSession与WMS进行系统通信
     mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,Looper.myLooper()),与requestLayout同在setView方法,View事件输入的接收器,接收来自于系统的事件
     view.assignParent(this),与requestLayout同在setView方法,assignParent方法在View类实现,将ViewRootImpl自己设置为DecorView的parent,所以ViewTree上的Root就是ViewRootImpl。

才疏学浅,如有错误,欢迎指正,多谢。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值