Analysis of requestLayout execution process in ListView

So what is the execution process of the requestLayout method, and what exactly does it do?
In addition, we also executed the requestLayout method in setAdapter, so we know that this method is very important for the drawing of the entire ListView. In fact, it is not only the ListView, but all Views.
Let’s first take a look at the setAdapter source code in ListView to see if the requestLayout method is executed.

@Override
public void setAdapter(ListAdapter adapter) {
    if (mAdapter != null & amp; & amp; mDataSetObserver != null) {
        mAdapter.unregisterDataSetObserver(mDataSetObserver);
    }

    resetList();
    mRecycler.clear();

    if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
        mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
    } else {
        mAdapter = adapter;
    }

    mOldSelectedPosition = INVALID_POSITION;
    mOldSelectedRowId = INVALID_ROW_ID;

    // AbsListView#setAdapter will update choice mode states.
    super.setAdapter(adapter);

    if (mAdapter != null) {
        mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
        mOldItemCount = mItemCount;
        mItemCount = mAdapter.getCount();
        checkFocus();

        mDataSetObserver = new AdapterDataSetObserver();
        mAdapter.registerDataSetObserver(mDataSetObserver);

        mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());

        int position;
        if (mStackFromBottom) {
            position = lookForSelectablePosition(mItemCount - 1, false);
        } else {
            position = lookForSelectablePosition(0, true);
        }
        setSelectedPositionInt(position);
        setNextSelectedPositionInt(position);

        if (mItemCount == 0) {
            // Nothing selected
            checkSelectionChanged();
        }
    } else {
        mAreAllItemsSelectable = true;
        checkFocus();
        // Nothing selected
        checkSelectionChanged();
    }

    requestLayout();
}

Just read the last sentence to know that there is indeed this method, and then follow the source code:
We found that ListView did not implement this method, so the requestLayout method of its parent class, AbsListView class, was executed:

@Override
public void requestLayout() {
    if (!mBlockLayoutRequests & amp; & amp; !mInLayout) {
        super.requestLayout();
    }
}

It doesn’t do much in this, it executes the requestLayout method of its parent class. Its parent class does not implement this method, and what is ultimately executed is View’s requestLayout method.
Go directly to the source code:

public class View implements Drawable.Callback, KeyEvent.Callback,
        AccessibilityEventSource {
    ...
    protected ViewParent mParent;

    AttachInfo mAttachInfo;

    public void requestLayout() {
        if (mMeasureCache != null) mMeasureCache.clear();

        if (mAttachInfo != null & amp; & amp; mAttachInfo.mViewRequestingLayout == null) {
            // Only trigger request-during-layout logic if this is the view requesting it,
            // not the views in its parent hierarchy
            ViewRootImpl viewRoot = getViewRootImpl();
            if (viewRoot != null & amp; & amp; viewRoot.isInLayout()) {
                if (!viewRoot.requestLayoutDuringLayout(this)) {
                    return;
                }
            }
            mAttachInfo.mViewRequestingLayout = this;
        }
        //Set the identifiers to PFLAG_FORCE_LAYOUT and PFLAG_INVALIDATED
        //From the English meaning, you can know that it is forced to relayout and redraw.
        mPrivateFlags |= PFLAG_FORCE_LAYOUT;
        mPrivateFlags |= PFLAG_INVALIDATED;

        //The requestLayout method of mParent will be executed here.
        if (mParent != null & amp; & amp; !mParent.isLayoutRequested()) {
            mParent.requestLayout();
        }
        if (mAttachInfo != null & amp; & amp; mAttachInfo.mViewRequestingLayout == this) {
            mAttachInfo.mViewRequestingLayout = null;
        }
    }

From the above, you can see that the requestLayout method of mParent will eventually be executed. mParent is a ViewParent class, which is an interface. The real requestLayout is implemented in its subclass, enter the ViewRootImpl source code

@Override
public void requestLayout() {
    if (!mHandlingLayoutInLayoutRequest) {
        //Make sure this call is executed in the UI thread
        checkThread();
        //The actual layout code will check this variable and decide whether it needs to be re-layout
        mLayoutRequested = true;
        //Initiate a message for View tree traversal, which is processed asynchronously
        //The corresponding processing function is performTraversals()
        scheduleTraversals();
    }
}

Take a look at the comments above. Finally, the scheduleTraversals method is executed, and then look at the source code:

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

We can see that it executes the postCallback method of mChoreographer, which is a Choreographer class.
We need to first talk about the mTraversalRunnable parameter in postCallback. It is actually a TraversalRunnable object. Let’s look at the definition source code:

final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

Let’s go to Choreographer’s postCallback function and follow it step by step. In fact, in the end, TraversalRunnable is put into the queue, and the run method of mTraversalRunnable will eventually be executed.

public final class Choreographer {

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

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

}

Looking at the internal source code, in the run method of mTraversalRunnable, the doTraversal() method is executed. Entering the doTraversal method, we can see that the performTraversals() method is executed.

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

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

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

            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals");
            try {
                performTraversals();
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            }

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

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. Java Skill TreeCollectionList Interface 138490 people are learning the system