In the “Android source graphical system window add” section left ViewRootImpl class setView method call requestLayout() function analysis. Now move on to analyzing the flow. Let’s take a look at the process before we analyze it.



The requestLayout() method primarily calls scheduleTraversals() for further processing.

frameworks/base/core/java/android/view/ViewRootImpl.java

public final class ViewRootImpl implements ViewParent.View.AttachInfo.Callbacks.HardwareRenderer.HardwareDrawCallbacks {...boolean mHandlingLayoutInLayoutRequest = false; .@Override
    public void requestLayout(a) {
        if(! mHandlingLayoutInLayoutRequest) { checkThread(); mLayoutRequested =true; scheduleTraversals(); }}... }Copy the code
  1. Post Traversal synchronization barrier
  2. Issue the CALLBACK_TRAVERSAL type callback to run on the next frame
  3. Consumption batch input
  4. Notify the Renderer of frame processing
  5. Get the Draw Lock as needed

frameworks/base/core/java/android/view/ViewRootImpl.java

public final class ViewRootImpl implements ViewParent.View.AttachInfo.Callbacks.HardwareRenderer.HardwareDrawCallbacks {...booleanmTraversalScheduled; .void scheduleTraversals(a) {
        if(! mTraversalScheduled) { mTraversalScheduled =true;
            // Post Traversal synchronization barrier
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            // Traversal callback Handles layout and drawing. Run after all other asynchronous messages have been processed.
            // Publish the callback to run on the next frame. The callback is run once and then automatically deleted.
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            if(! mUnbufferedInputDispatch) {// consume batch input
                scheduleConsumeBatchedInput();
            }
            // Notify Renderer of frame processing
            notifyRendererOfFramePending();
            // Get Draw Lock if neededpokeDrawLockIfNeeded(); }}... }Copy the code

TraversalRunnable the run() method only calls the doTraversal() method.

frameworks/base/core/java/android/view/ViewRootImpl.java

public final class ViewRootImpl implements ViewParent.View.AttachInfo.Callbacks.HardwareRenderer.HardwareDrawCallbacks {...final class TraversalRunnable implements Runnable {
        @Override
        public void run(a) { doTraversal(); }}final TraversalRunnable mTraversalRunnable = newTraversalRunnable(); . }Copy the code
  1. Remove Traversal synchronization barrier
  2. Call performTraversals() processing

frameworks/base/core/java/android/view/ViewRootImpl.java

public final class ViewRootImpl implements ViewParent.View.AttachInfo.Callbacks.HardwareRenderer.HardwareDrawCallbacks {...void doTraversal(a) {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            // Remove the Traversal synchronization barriermHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier); . performTraversals(); . }}... }Copy the code

Before going back to performTraversals(), I did a lot of logging in performTraversals(), which helps us understand how it works.

10-15 05:29:08.542 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: ===performTraversals() Begin===
10-15 05:29:08.546 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performTraversals desiredWindowWidth=1080 desiredWindowHeight=1776
10-15 05:29:08.546 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performTraversals measureHierarchy
10-15 05:29:08.546 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: Measuring com.android.internal.policy.PhoneWindow$DecorView{5fe490d V.E...... R.....ID 0,0-0,0} in display 1080x1776...
10-15 05:29:08.546 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: measureHierarchy performMeasure childWidthMeasureSpec=1073742904 childHeightMeasureSpec=1073743600
10-15 05:29:08.546 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performMeasure measure
10-15 05:29:08.555 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performTraversals layoutRequested=true
10-15 05:29:08.555 10604-10604/com.tyyj89.abdominalmusclepro I/ViewRootImpl: host=w:1080, h:1776, params=WM.LayoutParams{(0,0)(fillxfill) sim=#110 ty=1 fl=#81810100 wanim=0x103045b vsysui=0x1500 needsMenuKey=2}
10-15 05:29:08.557 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performTraversals relayoutWindow
10-15 05:29:08.557 10604-10604/com.tyyj89.abdominalmusclepro D/ViewRootImpl: WindowLayout in layoutWindow:WM.LayoutParams{(0,0)(fillxfill) sim=#110 ty=1 fl=#81810100 wanim=0x103045b vsysui=0x1500 needsMenuKey=2}
10-15 05:29:08.580 10604-10619/com.tyyj89.abdominalmusclepro V/ViewRootImpl: Resizing android.view.ViewRootImpl@9f26740: frame=[0,0][1080,1920] contentInsets=[0,72][0,144] visibleInsets=[0,72][0,144] reportDraw=true
10-15 05:29:08.589 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: relayout: frame=[0,0][1080,1920] overscan=[0,0][0,0] content=[0,72][0,144] visible=[0,72][0,144] visible=[0,72][0,144] outsets=[0,0][0,0] surface=Surface(name=null)/@0xd7a281f
10-15 05:29:08.590 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: Visible with new config: {1.0 460mcc2mnc zh_CN ldltr sw360dp w360dp h568dp 480dpi nrml port finger -keyb/v/h -nav/h s.5}
10-15 05:29:08.590 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performTraversals updateConfiguration
10-15 05:29:08.590 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: Applying new config to window com.tyyj89.abdominalmusclepro/com.tyyj89.abdominalmusclepro.ActionListActivity: {1.0 460mcc2mnc zh_CN ldltr sw360dp w360dp h568dp 480dpi nrml port finger -keyb/v/h -nav/h s.5}
10-15 05:29:08.590 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: Visible insets changing to: Rect(0, 72 - 0, 144)
10-15 05:29:08.591 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performTraversals Surface allocateBuffers mSurface=Surface(name=null)/@0xd7a281f
10-15 05:29:08.603 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: Relayout returned: frame=Rect(0, 0 - 1080, 1920), surface=Surface(name=null)/@0xd7a281f
10-15 05:29:08.603 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performTraversals HardwareRenderer setup
10-15 05:29:08.604 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: Ooops, something changed!  mWidth=1080 measuredWidth=1080 mHeight=1920 measuredHeight=1776 coveredInsetsChanged=false
10-15 05:29:08.604 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performTraversals performMeasure
10-15 05:29:08.604 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performMeasure measure
10-15 05:29:08.604 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performTraversals performLayout
10-15 05:29:08.604 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: Laying out com.android.internal.policy.PhoneWindow$DecorView{5fe490d V.E...... R.....ID 0,0-0,0} to (1080, 1920)
10-15 05:29:08.604 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performLayout layout
10-15 05:29:08.604 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: Invalidate child: Rect(0, 0 - 1080, 1920)
10-15 05:29:08.604 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: Invalidate child: Rect(0, 0 - 1080, 1776)
10-15 05:29:08.779 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: Invalidate child: Rect(0, 1776 - 1080, 1920)
10-15 05:29:08.779 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: Invalidate child: Rect(0, 0 - 1080, 72)
10-15 05:29:08.806 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performTraversals dispatchOnGlobalLayout
10-15 05:29:08.806 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: First: mView.hasFocus()=false
10-15 05:29:08.806 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: Request child focus: focus now android.widget.ListView{52e554b VFED.VC.. .F....ID 0,216-1080,1776 #7f08009e app:id/lv_action_list}
10-15 05:29:08.806 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: First: requested focused view=android.widget.ListView{52e554b VFED.VC.. .F....ID 0,216-1080,1776 #7f08009e app:id/lv_action_list}
10-15 05:29:08.806 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performTraversals mReportNextDraw=false
10-15 05:29:08.806 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performTraversals scheduleTraversals
10-15 05:29:08.806 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: ===performTraversals() End===
10-15 05:29:08.806 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: ===performTraversals() Begin===
10-15 05:29:08.822 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performTraversals performDraw
10-15 05:29:08.822 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performDraw draw
10-15 05:29:08.822 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: draw fullRedrawNeeded=false
10-15 05:29:08.822 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: Draw com.android.internal.policy.PhoneWindow$DecorView{87e9ce8 V.E...... R....... 0,0-1080,1920}/com.tyyj89.abdominalmusclepro/com.tyyj89.abdominalmusclepro.MainActivity: dirty={0,0,1080,1920} surface=Surface(name=null)/@0x8ff2763 surface.isValid()=true, appScale:1.0, width=1080, height=1920
10-15 05:29:08.822 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: draw HardwareRenderer draw mView=com.android.internal.policy.PhoneWindow$DecorView{87e9ce8 V.E...... R....... 0,0-1080,1920} mAttachInfo=android.view.View$AttachInfo@7d681b6
10-15 05:29:08.824 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: ===performTraversals() End===
10-15 05:29:08.826 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: ===performTraversals() Begin===
10-15 05:29:08.862 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performTraversals measureHierarchy
10-15 05:29:08.862 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: Measuring com.android.internal.policy.PhoneWindow$DecorView{5fe490d V.E...... R.....ID 0,0-1080,1920} in display 1080x1920...
10-15 05:29:08.862 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: measureHierarchy performMeasure childWidthMeasureSpec=1073742904 childHeightMeasureSpec=1073743744
10-15 05:29:08.862 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performMeasure measure
10-15 05:29:08.883 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performTraversals layoutRequested=true
10-15 05:29:08.883 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performTraversals performLayout
10-15 05:29:08.883 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: Laying out com.android.internal.policy.PhoneWindow$DecorView{5fe490d V.E...... R.....ID 0,0-1080,1920} to (1080, 1920)
10-15 05:29:08.883 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performLayout layout
10-15 05:29:08.901 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performTraversals dispatchOnGlobalLayout
10-15 05:29:08.901 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performTraversals performDraw
10-15 05:29:08.901 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performDraw draw
10-15 05:29:08.901 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: draw fullRedrawNeeded=true
10-15 05:29:08.901 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: Draw com.android.internal.policy.PhoneWindow$DecorView{5fe490d V.E...... R.....ID 0,0-1080,1920}/com.tyyj89.abdominalmusclepro/com.tyyj89.abdominalmusclepro.ActionListActivity: dirty={0,0,1080,1920} surface=Surface(name=null)/@0xd7a281f surface.isValid()=true, appScale:1.0, width=1080, height=1920
10-15 05:29:08.901 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: draw HardwareRenderer draw mView=com.android.internal.policy.PhoneWindow$DecorView{5fe490d V.E...... R.....ID 0,0-1080,1920} mAttachInfo=android.view.View$AttachInfo@3d61fde
10-15 05:29:08.939 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: FINISHED DRAWING: com.tyyj89.abdominalmusclepro/com.tyyj89.abdominalmusclepro.ActionListActivity
10-15 05:29:08.939 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: performDraw WindowSession finishDrawing
10-15 05:29:08.942 10604-10604/com.tyyj89.abdominalmusclepro V/ViewRootImpl: ===performTraversals() End===
Copy the code

The key steps are summarized below:

  1. Call measureHierarchy (…). Measure the layer and the measurement will be performed internally
  2. Relayout the window
  3. Surface allocated Buffer
  4. The measurement is performed a second time
  5. Perform layout
  6. Perform rendering

frameworks/base/core/java/android/view/ViewRootImpl.java

public final class ViewRootImpl implements ViewParent.View.AttachInfo.Callbacks.HardwareRenderer.HardwareDrawCallbacks {...private void performTraversals(a) {
        // Cache mView as it is often used below...
        finalView host = mView; .if (host == null| |! mAdded)return;

        mIsInTraversal = true;
        mWillDrawSoon = true;
        boolean windowSizeMayChange = false;
        boolean newSurface = false;
        boolean surfaceChanged = false;
        WindowManager.LayoutParams lp = mWindowAttributes;

        int desiredWindowWidth;
        intdesiredWindowHeight; . Rect frame = mWinFrame;if (mFirst) {
            mFullRedrawNeeded = true;
            mLayoutRequested = true;

            if(lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {... }else {
                // The width and height of the DecorView window are the width and height of the entire screenDisplayMetrics packageMetrics = mView.getContext().getResources().getDisplayMetrics(); desiredWindowWidth = packageMetrics.widthPixels; desiredWindowHeight = packageMetrics.heightPixels; }... }else{... }...booleanlayoutRequested = mLayoutRequested && (! mStopped || mReportNextDraw);if (layoutRequested) {

            final Resources res = mView.getContext().getResources();

            if (mFirst) {
                // Make sure to execute the touch mode code.mAttachInfo.mInTouchMode = ! mAddedTouchMode; ensureTouchModeLocally(mAddedTouchMode); }else{... }// 1. Measure the layerwindowSizeMayChange |= measureHierarchy(host, lp, res, desiredWindowWidth, desiredWindowHeight); }...if (layoutRequested) {
            // Now clear it so that if there are any request layouts in the rest of the function,
            // We'll capture it and rerun the full layout traversal.
            mLayoutRequested = false; }...int relayoutResult = 0;

        if(mFirst || windowShouldResize || insetsChanged || viewVisibilityChanged || params ! =null) {...boolean hwInitialized = false;
            boolean contentInsetsChanged = false;
            boolean hadSurface = mSurface.isValid();

            try{...// 2. Rearrange the window
                relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);

                if(mPendingConfiguration.seq ! =0) {
                    // Update the configurationupdateConfiguration(mPendingConfiguration, ! mFirst); mPendingConfiguration.seq =0; }...if(! hadSurface) {if (mSurface.isValid()) {
                        // If we want to create a new Surface,
                        // Then we need to completely redraw it.
                        // Also, when we draw it, we will defer and arrange a new Traversal.
                        // So that we can tell the window manager all the Windows that are being displayed before the actual drawing,
                        // So it can display all the Windows at once.
                        newSurface = true;
                        mFullRedrawNeeded = true;
                        mPreviousTransparentRegion.setEmpty();

                        // Preinitialize only if the transparent area is not requested, otherwise postpone seeing if the entire window is transparent
                        if(mAttachInfo.mHardwareRenderer ! =null) {
                            try {
                                hwInitialized = mAttachInfo.mHardwareRenderer.initialize(
                                        mSurface);
                                if (hwInitialized && (host.mPrivateFlags
                                        & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) {
                                    // If transparent areas are requested, do not pre-allocate them, as they may not be required
                                    // allocate BuffermSurface.allocateBuffers(); }}catch (OutOfResourcesException e) {
                                handleOutOfResourcesException(e);
                                return; }}}}else if(! mSurface.isValid()) { ...... }else if(surfaceGenerationId ! = mSurface.getGenerationId() && mSurfaceHolder ==null&& mAttachInfo.mHardwareRenderer ! =null) {... }}catch(RemoteException e) { } mAttachInfo.mWindowLeft = frame.left; mAttachInfo.mWindowTop = frame.top; .final HardwareRenderer hardwareRenderer = mAttachInfo.mHardwareRenderer;
            if(hardwareRenderer ! =null && hardwareRenderer.isEnabled()) {
                if(hwInitialized || mWidth ! = hardwareRenderer.getWidth() || mHeight ! = hardwareRenderer.getHeight()) { hardwareRenderer.setup(mWidth, mHeight, mAttachInfo, mWindowAttributes.surfaceInsets);if(! hwInitialized) { ...... }}}if(! mStopped || mReportNextDraw) {booleanfocusChangedDueToTouchMode = ensureTouchModeLocally( (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) ! =0);
                if(focusChangedDueToTouchMode || mWidth ! = host.getMeasuredWidth() || mHeight ! = host.getMeasuredHeight() || contentInsetsChanged) {int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
                    int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);

                    // 4. Perform the second measurementperformMeasure(childWidthMeasureSpec, childHeightMeasureSpec); . layoutRequested =true; }}}else{... }final booleandidLayout = layoutRequested && (! mStopped || mReportNextDraw);boolean triggerGlobalLayoutListener = didLayout
                || mAttachInfo.mRecomputeGlobalAttributes;
        if (didLayout) {
            // 5. Execute layout
            performLayout(lp, desiredWindowWidth, desiredWindowHeight);

            // Now that the size and position of all views are determined, we can calculate the transparent area
            if((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) ! =0) {
                // start out transparent
                // TODO: AVOID THAT CALL BY CACHING THE RESULT?
                host.getLocationInWindow(mTmpLocation);
                mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
                        mTmpLocation[0] + host.mRight - host.mLeft,
                        mTmpLocation[1] + host.mBottom - host.mTop);

                host.gatherTransparentRegion(mTransparentRegion);
                if(mTranslator ! =null) {
                    mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
                }

                if(! mTransparentRegion.equals(mPreviousTransparentRegion)) { mPreviousTransparentRegion.set(mTransparentRegion); mFullRedrawNeeded =true;
                    // Reconfigure window manager
                    try {
                        mWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
                    } catch (RemoteException e) {
                    }
                }
            }

        }
        // Trigger the global layout listener
        if (triggerGlobalLayoutListener) {
            mAttachInfo.mRecomputeGlobalAttributes = false; mAttachInfo.mTreeObserver.dispatchOnGlobalLayout(); }...boolean skipDraw = false;

        if (mFirst) {
            // Process the first focus request
            if(mView ! =null) {
                if(! mView.hasFocus()) { mView.requestFocus(View.FOCUS_FORWARD); }else{... }}}else if (mWindowsAnimating) {
            if (mRemainingFrameCount <= 0) {
                skipDraw = true;
            }
            mRemainingFrameCount--;
        }

        mFirst = false;
        mWillDrawSoon = false;
        mNewSurfaceNeeded = false; mViewVisibility = viewVisibility; .// Remember if we have to report the next draw.
        if((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) ! =0) {
            mReportNextDraw = true;
        }

        booleancancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || viewVisibility ! = View.VISIBLE;if(! cancelDraw && ! newSurface) {if(! skipDraw || mReportNextDraw) { ......// 6. Perform the drawingperformDraw(); }}else {
            if (viewVisibility == View.VISIBLE) {
                // Arrange Traversals again
                scheduleTraversals();
            } else if(mPendingTransitions ! =null && mPendingTransitions.size() > 0) {... } } mIsInTraversal =false; }... }Copy the code

Lp. The width is not equal to ViewGroup. LayoutParams. WRAP_CONTENT, so will perform! GoodMeasure branch, which further executes performMeasure(…) Function.

frameworks/base/core/java/android/view/ViewRootImpl.java

public final class ViewRootImpl implements ViewParent.View.AttachInfo.Callbacks.HardwareRenderer.HardwareDrawCallbacks {...private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
            final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {
        int childWidthMeasureSpec;
        int childHeightMeasureSpec;
        boolean windowSizeMayChange = false;
        boolean goodMeasure = false;
        if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
            ......
        }

        if(! goodMeasure) { childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width); childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height); performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);if(mWidth ! = host.getMeasuredWidth() || mHeight ! = host.getMeasuredHeight()) { windowSizeMayChange =true; }}returnwindowSizeMayChange; }... }Copy the code

PerformMeasure (…). The function is very simple, just calls the mView’s measure(…). Methods. Call to measure (…). The function is to determine how big the view should be. The parent element provides constraint information in the width and height parameters. The actual measurement of the view is performed in onMeasure(int, int), which is called by this method. Therefore, only onMeasure(int, int) can and must be overridden by subclasses. This is the first part of our trilogy of custom Views.

frameworks/base/core/java/android/view/ViewRootImpl.java

public final class ViewRootImpl implements ViewParent.View.AttachInfo.Callbacks.HardwareRenderer.HardwareDrawCallbacks {...private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
        try {
            mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
        } finally{ Trace.traceEnd(Trace.TRACE_TAG_VIEW); }}... }Copy the code

To rearrange the window is to call relayoutWindow(…) Function implementation, will be analyzed in detail later. The Surface allocation Buffer will not be analyzed in depth for the time being.

Since the height of the window does not fill the screen, the height of the status bar and the height of the bottom button bar need to be subtracted, so the measurement will be performed a second time, which is a direct call to performMeasure(…). .

The layout is then executed. This is implemented by calling the mView Layout function. The Layout function specifies the size and position of the view and all its descendants. This is the second stage of the layout mechanism (measurement first). In this phase, each parent node calls the layout of all its children to locate them. Derived classes should not override this method. Derived classes with subclasses should override onLayout. In this method, they should call Layout on each child node.

frameworks/base/core/java/android/view/ViewRootImpl.java

public final class ViewRootImpl implements ViewParent.View.AttachInfo.Callbacks.HardwareRenderer.HardwareDrawCallbacks {...private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
            int desiredWindowHeight) {
        mLayoutRequested = false;
        mScrollMayChange = true;
        mInLayout = true;

        final View host = mView;
        if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
            Log.v(TAG, "Laying out " + host + " to (" +
                    host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
        }

        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
        try {
            host.layout(0.0, host.getMeasuredWidth(), host.getMeasuredHeight()); . }finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
        mInLayout = false; }... }Copy the code

Finally, the drawing is performed. From Log, you can see that the first time you go into performTraversals() the target View is not painted, and the second time (or rather, the second time you start processing the target View) the target View is actually painted. Here we call draw(…) Methods.

frameworks/base/core/java/android/view/ViewRootImpl.java

public final class ViewRootImpl implements ViewParent.View.AttachInfo.Callbacks.HardwareRenderer.HardwareDrawCallbacks {...private void performDraw(a) {
        if(mAttachInfo.mDisplayState == Display.STATE_OFF && ! mReportNextDraw) {return;
        }

        final boolean fullRedrawNeeded = mFullRedrawNeeded;
        mFullRedrawNeeded = false;

        mIsDrawing = true;
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
        try {
            draw(fullRedrawNeeded);
        } finally {
            mIsDrawing = false; Trace.traceEnd(Trace.TRACE_TAG_VIEW); }...if (mReportNextDraw) {
            mReportNextDraw = false;
            if(mAttachInfo.mHardwareRenderer ! =null) {
                mAttachInfo.mHardwareRenderer.fence();
            }

            if (LOCAL_LOGV) {
                Log.v(TAG, "FINISHED DRAWING: "+ mWindowAttributes.getTitle()); }...try {
                mWindowSession.finishDrawing(mWindow);
            } catch (RemoteException e) {
            }
        }
    }
    ......
}
Copy the code

Call HardwareRenderer class (HardwareRenderer) draw method to draw the View, if the HardwareRenderer is not enabled drawSoftware(…) Implement “soft drawing”. More on hardware renderers later. DrawSoftware (…). The View’s draw method is called internally.

frameworks/base/core/java/android/view/ViewRootImpl.java

public final class ViewRootImpl implements ViewParent.View.AttachInfo.Callbacks.HardwareRenderer.HardwareDrawCallbacks {...private void draw(boolean fullRedrawNeeded) {
        Surface surface = mSurface;
        if(! surface.isValid()) {return; }...if(! dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {if(mAttachInfo.mHardwareRenderer ! =null && mAttachInfo.mHardwareRenderer.isEnabled()) {
                ......
                mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this);
            } else{...if(! drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {return; }}}... }... }Copy the code

At this point we have implemented the drawing of the DecorView, although how it relates to the underlying layer needs further clarification.