Parse the view. post method. Analyze the flow of this method.

The post method is a Runnable object that receives a Runnable object. So what’s the difference between these two approaches?

The POST method of the Handler

First, take a quick look at the Handler’s POST (Runnable) method. This method adds a Runnable to the message queue and is executed in the thread associated with the handler.

Below is the associated partial source code. You can see that the incoming Runnable object, loaded with Message, is added to the queue.

Handler related part of the source code

    // Android. OS Handler for the source code
    public final boolean post(@NonNull Runnable r) {
        return sendMessageDelayed(getPostMessage(r), 0);
    }

    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

    public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

    public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

    private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
Copy the code

For details about the process, see Handler

View post method

Let’s just follow post’s source code.

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

private HandlerActionQueue getRunQueue(a) {
    if (mRunQueue == null) {
        mRunQueue = new HandlerActionQueue();
    }
    return mRunQueue;
}
Copy the code

As you can see, the initial query is for attachInfo, and if so, the attachInfo.mHandler is used to perform this task.

If there is no attachInfo, add it to the View’s own mRunQueue. Determine the thread to run before executing the task.

Post (Runnable Action) returns a Boolean value, if true, indicating that the task has been added to the message queue. False usually indicates that the looper associated with the message queue is exiting.

So we need to know about AttachInfo and HandlerActionQueue.

AttachInfo

AttachInfo is the static inner class of the View. Once the View is associated with the parent window, it uses this class to store some information.

AttachInfo Stores some of the following information:

  • WindowId mWindowIdA sign of the window
  • View mRootViewThe view at the top
  • Handler mHandlerThis handler can be used to process tasks

HandlerActionQueue

When the View doesn’t have a handler, use the HandlerActionQueue to cache tasks. HandlerAction is its static inner class that stores Runnable and delay information.

public class HandlerActionQueue {
    private HandlerAction[] mActions;
    
    public void post(Runnable action)
    public void executeActions(Handler handler)
    // ...

    private static class HandlerAction {
        final Runnable action;
        final long delay;
        // ...}}Copy the code

The View of mRunQueue

Runnable tasks into a queue. These tasks are performed when the View is associated with a window and there is a handler.

/** * Queue of pending runnables. Used to postpone calls to post() until this * view is attached and has a handler. */
private HandlerActionQueue mRunQueue;
Copy the code

When will the task stored in the mRunQueue be executed? Let’s focus on the dispatchAttachedToWindow method.

void dispatchAttachedToWindow(AttachInfo info, int visibility) {
    // ...
    // Transfer all pending runnables.
    if(mRunQueue ! =null) {
        mRunQueue.executeActions(info.mHandler);
        mRunQueue = null;
    }
    // ...
}
Copy the code

This method calls mrunqueue.executeActions.

The executeActions(Handler Handler) method actually uses the Handler passed in to process the tasks in the queue.

And this dispatchAttachedToWindow is going to be called in the ViewGroup.

Or call it in view rule PL

host.dispatchAttachedToWindow(mAttachInfo, 0);
Copy the code

summary

The View post method actually uses the AttachInfo handler.

If the View does not currently have AttachInfo, the task is added to the View’s own HandlerActionQueue queue and then handed to the incoming AttachInfo handler in dispatchAttachedToWindow. You can also think of view.post as using handler.post.

When we get the width and height of the View, we will use the View post method, which is to wait until the View is actually associated with the window to get the width and height information.

The flow chart is summarized as follows