代码调用流程图

Android UI绘制流程

代码相关思维导图

UI绘制入口

ActivityThread

在Activity的生命周期中,系统服务AMS会调用到ActivityThread中的handleResumeActivity方法,在这个方法中,可以看到:

@Override

public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason) {
    // ...
    // TODO Push resumeArgs into the activity for consideration
    final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
    if (r == null) {
        // We didn't actually resume the activity, so skipping any follow-up actions.
        return;
    }

    // ...
    if (r.window == null && !a.mFinished && willBeVisible) {
        // 获取window
        r.window = r.activity.getWindow();
        // 获取decor
        View decor = r.window.getDecorView();
        // 先将decorView设置不可见
        decor.setVisibility(View.INVISIBLE);
        // 获取windowManager
        ViewManager wm = a.getWindowManager();
        WindowManager.LayoutParams l = r.window.getAttributes();
        a.mDecor = decor;
        // 设置window的层级
        l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
           // ...
        if (a.mVisibleFromClient) {
            if (!a.mWindowAdded) {
                a.mWindowAdded = true;
                wm.addView(decor, l);
            }
            // ...
        }
        // ...
    }

    // Get rid of anything left hanging around.
    cleanUpPendingRemoveWindows(r, false /* force */);
    // The window is now visible if it has been added, we are not
    // simply finishing, and we are not starting another activity.
    if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
        // ...
        // 设置decor可见
        if (r.activity.mVisibleFromClient) {
            r.activity.makeVisible();
        }
    }
    // ...
}
  1. 获取activity中的window;
  2. 获取window中的decorView并设置为不可见;
  3. 获取windowManager并调用addView方法添加decorView;
  4. 添加完毕后,通过activity.makeVisible()设置decorView可见。

WindowManager

我们知道WindowManager是用来管理view窗口的,它是ViewManager的子类,它的实现类是WindowManagerImpl

public interface WindowManager extends ViewManager {}
public interface ViewManager{
    // 添加view
    public void addView(View view, ViewGroup.LayoutParams params);
    // 更新布局
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    // 移除view
    public void removeView(View view);
}
public final class WindowManagerImpl implements WindowManager {
    // windowManager中持有一个WindowManagerGlobal单例
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
}

addView

在上面handleResumeActivity中调用了WindowManageraddView方法。在 addView中:

@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    // 调用了WindowManagerGlobal中的addView方法
    mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}

WindowManagerImpladdView中调用了WindowManagerGlobaladdView

public void addView(View view, ViewGroup.LayoutParams params,
                    Display display, Window parentWindow) {
    // ...
    final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
    if (parentWindow != null) {
        parentWindow.adjustLayoutParamsForSubWindow(wparams);
    } else {
        // If there's no parent, then hardware acceleration for this view is
        // set from the application's hardware acceleration setting.
        final Context context = view.getContext();
        if (context != null
            && (context.getApplicationInfo().flags
                & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
            wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
        }
    }
    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) {
            // BadTokenException or InvalidDisplayException, clean up.
            if (index >= 0) {
                removeViewLocked(index, true);
            }
            throw e;
        }
    }
}

mViews保存的是View对象,DecorView
mRoots保存和顶层View关联的ViewRootImpl对象
mParams保存的是创建顶层View的layout参数。
调用root.setView将参数和视图同时交给了ViewRootImpl

public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {}
public interface ViewParent {}

ViewRootImpl

setView

/**
  * We have one child
  */
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    synchronized (this) {
        if (mView == null) {
            mView = view;
            // ...
            mAdded = true;
            int res; /* = WindowManagerImpl.ADD_OKAY; */
            // 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();
            // ...
            try {
                // ...
                res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, 
                                                  getHostVisibility(),
                                                  mDisplay.getDisplayId(),
                                                  mTmpFrame,
                                                  mAttachInfo.mContentInsets,
                                                  mAttachInfo.mStableInsets,
                                                  mAttachInfo.mOutsets,
                                                  mAttachInfo.mDisplayCutout, mInputChannel,  mTempInsets);
                setFrame(mTmpFrame);
            } catch (RemoteException e) {
                // ...
                throw new RuntimeException("Adding window failed", e);
            } finally {
                if (restore) {
                    attrs.restore();
                }
            }
            // ...
            view.assignParent(this);
            // ...
        }
    }
}

requestLayout

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

scheduleTraversals

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

mTraversalRunnable

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

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

private void performTraversals() {
    // ...
    if (mFirst || windowShouldResize || insetsChanged ||
        viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
        mForceNextWindowRelayout = false;
        // ...
        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
                performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
                // Implementation of weights from WindowManager.LayoutParams
                // We just grow the dimensions as needed and re-measure if
                // needs be
                int width = host.getMeasuredWidth();
                int height = host.getMeasuredHeight();
                boolean measureAgain = false;
                if (lp.horizontalWeight > 0.0f) {
                    width += (int) ((mWidth - width) * lp.horizontalWeight);
                    childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
                    MeasureSpec.EXACTLY);
                    measureAgain = true;
                }
                if (lp.verticalWeight > 0.0f) {
                    height += (int) ((mHeight - height) * lp.verticalWeight);
                    childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
                    measureAgain = true;
                }
                if (measureAgain) {
                    // 进行UI布局的测量
                    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
                }
                layoutRequested = true;
            }
        }
    }
    // ...
    final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
    boolean triggerGlobalLayoutListener = didLayout
        || mAttachInfo.mRecomputeGlobalAttributes;
    if (didLayout) {
        // 进行UI控件的摆放
        performLayout(lp, mWidth, mHeight);
        // ...
    }
    // Remember if we must report the next draw.
    if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
        reportNextDraw();
    }
    boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
    if (!cancelDraw) {
        if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
            for (int i = 0; i < mPendingTransitions.size(); ++i) {
                mPendingTransitions.get(i).startChangingAnimations();
            }
            mPendingTransitions.clear();
        }
        // 进行图形的绘画
        performDraw();
    } else {
        if (isViewVisible) {
            // Try again
            scheduleTraversals();
        } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
            for (int i = 0; i < mPendingTransitions.size(); ++i) {
                mPendingTransitions.get(i).endChangingAnimations();
            }
            mPendingTransitions.clear();
        }
    }
    mIsInTraversal = false;
}

performTravals()中主要调用了performMeasure()performLayout()performDraw()来进行UI的测量、布局和绘制。