从源码分析 Activity 启动的时候 View 是何时且如何显示到屏幕上的

从源码分析 Activity 启动的时候 View 是何时且如何显示到屏幕上的

这篇文章的重点通过源码分析 Activity 启动的时候 View 是何时且如何显示到屏幕上的

Activity 启动的生命周期

学习 Android 应该都知道 Activity 启动的生命周期,毕竟刚开始学都是从生命周期入手的

onCreate
onStart
onResume

你虽然知道 Activity 启动的生命周期,但是你是否有疑惑过屏幕上的 View 是何时显示出来的?到底是怎么显示的?

从源码分析 View 是何时且如何显示到屏幕上的

看过 Activity 启动的生命周期源码的,应该对 ResumeActivityItem 都不陌生

ResumeActivityItem 就是在执行 Activity onResume 生命周期的时候 ActivityManagerService 通过 Binder 传给 ActivityThread 的消息

通知 ActivityThread 真正去执行 Activity 的 onResume 方法

android\app\servertransaction\ResumeActivityItem.java

public void execute(ClientTransactionHandler client, IBinder token,
        PendingTransactionActions pendingActions) {
    Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
    client.handleResumeActivity(token, true /* finalStateRequest */, mIsForward,
            "RESUME_ACTIVITY");
    Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}

其实最终还是回到了 ActivityThread 里面实现了 handleResumeActivity 方法,这个方法分为了两个步骤

  1. 真正执行 Activity 的 onResume 方法
  2. 把根 View 加入到 WindowManager 里面,然后开始渲染展示根 View

android\app\ActivityThread.java
public final class ActivityThread extends ClientTransactionHandler

public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
        String reason) {
    ...

    // TODO Push resumeArgs into the activity for consideration
    // 1. 真正执行 Activity 的 onResume 方法
    final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
    
    ...

    if (r.window == null && !a.mFinished && willBeVisible) {
        r.window = r.activity.getWindow();
        View decor = r.window.getDecorView();
        decor.setVisibility(View.INVISIBLE);
        ViewManager wm = a.getWindowManager();
        
        ...

        // 2. 把根 View 加入到 WindowManager 里面,然后开始渲染展示根 View
        if (a.mVisibleFromClient) {
            if (!a.mWindowAdded) {
                a.mWindowAdded = true;
                wm.addView(decor, l);
            } else { ... }
        }
    } else if (!willBeVisible) { ... }

    ...
}

首先看下第一个步骤,performResumeActivity 是如何执行 Activity 的 onResume 方法的

这里很直接,直接调用了 Activity 的 performResume 方法

android\app\ActivityThread.java

public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest,
        String reason) {
    ...

    try {
        ...

        r.activity.performResume(r.startsNotResumed, reason);

        r.state = null;
        r.persistentState = null;
        r.setState(ON_RESUME);
    } catch (Exception e) { ... }
    return r;
}

下面就是一步步最终调用 Activity 的 onResume 方法

Activity#performResume() --> Instrumentation#callActivityOnResume() --> Activity#onResume()

android\app\Activity.java

final void performResume(boolean followedByPause, String reason) {
    performRestart(true /* start */, reason);

    mFragments.execPendingActions();

    ...

    mCalled = false;
    // mResumed is set by the instrumentation
    mInstrumentation.callActivityOnResume(this);
    
    ...

    mFragments.dispatchResume();
    mFragments.execPendingActions();

    onPostResume();
}

android\app\Instrumentation.java

public void callActivityOnResume(Activity activity) {
    activity.mResumed = true;
    activity.onResume();
    
    if (mActivityMonitors != null) {
        synchronized (mSync) {
            final int N = mActivityMonitors.size();
            for (int i=0; i<N; i++) {
                final ActivityMonitor am = mActivityMonitors.get(i);
                am.match(activity, activity, activity.getIntent());
            }
        }
    }
}

android\app\Activity.java

protected void onResume() {
    if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
    getApplication().dispatchActivityResumed(this);
    mActivityTransitionState.onResume(this, isTopOfTask());
    if (mAutoFillResetNeeded) { ... }
    mCalled = true;
}

我们返回前面的第二个步骤

如何把根 View 加入到 WindowManager 里面,然后开始渲染展示根 View

这里面传过来的 view = DecorView, 也就是 Activity 的根 View

android\view\WindowManagerImpl.java

private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();

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

最终实现其实都是由 WindowManagerGlobal 做的

  1. 创建出 ViewRootImpl
  2. 给 ViewRootImpl 设置具体的 DecorView

android\view\WindowManagerGlobal.java

public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow) {
    ...

    ViewRootImpl root;
    View panelParentView = null;

    synchronized (mLock) {
        ...

        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);
        } catch (RuntimeException e) { ... }
    }
}

在给 ViewRootImpl 设置具体的 DecorView 的时候,其实就是要做布局的操作了

android\view\ViewRootImpl.java

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

            ...

            // Schedule the first layout -before- adding to the window
            // manager, to make sure we do the relayout before receiving
            // any other events from the system.
            requestLayout();

            ...
        }
    }
}

一步步查看实现 Layout 的地方,Choreographer 编导者是有固定的的回调时间的,通知进行绘制(大概间隔 15ms, 也就是我们常说的 60 帧)

android\view\ViewRootImpl.java

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

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


final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

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



void doTraversal() {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

        if (mProfile) {
            Debug.startMethodTracing("ViewAncestor");
        }

        performTraversals();

        if (mProfile) {
            Debug.stopMethodTracing();
            mProfile = false;
        }
    }
}

最后就是在 performTraversals 里面执行绘制的三个步骤

  1. Measure
  2. Layout
  3. Draw

android\view\ViewRootImpl.java

private void performTraversals() {

    ...

        if (!mStopped || mReportNextDraw) {
            boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
                    (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
            if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
                    || mHeight != host.getMeasuredHeight() || contentInsetsChanged ||
                    updatedConfiguration) {
                int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
                int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);

                 // Ask host how big it wants to be
                // 1. Measure
                performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);

                ...

                layoutRequested = true;
            }
        }
    } else { ... }

    final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
    boolean triggerGlobalLayoutListener = didLayout
            || mAttachInfo.mRecomputeGlobalAttributes;
    if (didLayout) {
        // 2. Layout
        performLayout(lp, mWidth, mHeight);

        ...
    }

    ...

    if (!cancelDraw && !newSurface) {
        if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
            for (int i = 0; i < mPendingTransitions.size(); ++i) {
                mPendingTransitions.get(i).startChangingAnimations();
            }
            mPendingTransitions.clear();
        }

        // 3. Draw
        performDraw();
    } else { ... }

    mIsInTraversal = false;
}

总结

DecorView 最终显示在屏幕上是在 onResume 阶段做的,但是要晚于 onResume 的操作

DecorView 显示的过程也就是 View 绘制的三个步骤: Measure, Layout, Draw

猜你喜欢

转载自blog.csdn.net/qq_16927853/article/details/109097286