I think you’ve all had this problem at work, Solution generally have the post (Runnable), the getViewTreeObserver () addOnGlobalLayoutListener (OnGlobalLayoutListener listener). View. Post (Runnable) method:

public boolean post(Runnable action) {
        final AttachInfo attachInfo = mAttachInfo;
        if(attachInfo ! = null) {return attachInfo.mHandler.post(action);
        }

        // Postpone the runnable until we know on which thread it needs to run.
        // Assume that the runnable will be successfully placed after attach.
        getRunQueue().post(action);
        return true;
    }
Copy the code

As you can see, attachInfo is not empty; attachInfo.mHandler is called to handle this action, otherwise getRunQueue().post(action) is called. Take a look at getRunQueue() :

private HandlerActionQueue getRunQueue() {
        if (mRunQueue == null) {
            mRunQueue = new HandlerActionQueue();
        }
        return mRunQueue;
    }
    
public class HandlerActionQueue {
    private HandlerAction[] mActions;
    private int mCount;

    public void post(Runnable action) {
        postDelayed(action, 0);
    }

    public void postDelayed(Runnable action, long delayMillis) {
        final HandlerAction handlerAction = new HandlerAction(action, delayMillis);

        synchronized (this) {
            if(mActions == null) { mActions = new HandlerAction[4]; } mActions = GrowingArrayUtils.append(mActions, mCount, handlerAction); mCount++; }}... }Copy the code

This creates a queue (array) for handlerActions, and all tasks that were previously sent in via POST are stored in this queue when mAttachInfo == NULL. The queue has an initial size of 4 and can be expanded by GrowingArrayUtils. HandlerAction is a simple class that encapsulates Runnable and delay(long). The HandlerAction in the queue is executed as follows:

public void executeActions(Handler handler) {
        synchronized (this) {
            final HandlerAction[] actions = mActions;
            for(int i = 0, count = mCount; i < count; i++) { final HandlerAction handlerAction = actions[i]; handler.postDelayed(handlerAction.action, handlerAction.delay); } mActions = null; mCount = 0; }}Copy the code

ExecuteActions () calls four different places, one in the View and three in the ViewGroup. The position of the call in the View is:

void dispatchAttachedToWindow(AttachInfo info, int visibility) {
       ** mAttachInfo = info**;
        if(mOverlay ! = null) { mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); } mWindowAttachCount++; // We will need to evaluate the drawable state at least once. mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY;if(mFloatingTreeObserver ! = null) { info.mTreeObserver.merge(mFloatingTreeObserver); mFloatingTreeObserver = null; } registerPendingFrameMetricsObservers();if((mPrivateFlags&PFLAG_SCROLL_CONTAINER) ! = 0) { mAttachInfo.mScrollContainers.add(this); mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; } // Transfer all pending runnables.if(mRunQueue ! = null) { **mRunQueue**.executeActions(info.mHandler); mRunQueue = null; } performCollectViewAttributes(mAttachInfo, visibility); onAttachedToWindow(); . }Copy the code

Let’s see what the method name means: Distribute an operation that appends the View to the Window. Why is it possible to call mrunqueue.executeActions () in this method to perform all previously stored tasks, The answer, of course, is that mAttachInfo = info is assigned on the first line, and the handler that handles the tasks in the mRunQueue is in mAttachInfo:

/**
* A Handler supplied by a view's {@link android.view.ViewRootImpl}. This * handler can be used to pump events in the UI events queue. * This handler can pass events to the UI thread for processing.Copy the code

I’m guessing here that the handler is the UI thread that gives the View to the View and the View gives the View to the View. (Please point out any mistakes)

Similarly, dispatchAttachedToWindow() in ViewGroup recursively traversals all sub-views in performTraversals() in ViewRootImpl and pays mAttachInfo to all sub-views, Here the mAttachInfo of the ViewGroup and the subview are the same.

In the performTraversals() method, performMeasure() at line 2155, performLayout() at line 2200, and performDraw() at line 2347; “DispatchAttachedToWindow ()” (1658), “View” (1658), “View” (1658), “View” (1658), “View” (1658)” PerformTraversals () and dispatchAttachedToWindow() are both ultimately transitioned bits taken from the Message by Looper and executed in order.

View.post () is cached before mAttachInfo == null and executed after mAttachInfo is assigned. After that, if any other tasks are posted, they will be executed immediately.

Refer to the article: www.cnblogs.com/dasusu/p/80…