preface

View.post and handler. post are two “post” methods commonly used in Android development. We often use the former to get some View rendering data at runtime, or to measure the rendering time of a page. The latter, in turn, is a method of Android’s core Handler that inserts a Message into the corresponding thread’s MessageQueue to be executed….. at some future event point

Why compare the two?

First of all, they have the same name

Second, the timing of view.post () is closely related to the drawing and rendering of the entire View. The basis of all this is handler.post () on the main thread. Clearing up the relationship between the two can deepen our understanding of the process of rendering and drawing a View.

View rendering starting point

Broadly, when the DecorView is “attached” to the Window, the View will begin to render when the application receives the synchronization signal assigned to each Activity by the system. ChoreoGrapher will send out a signal to tell ViewRootImpl to render the view, so each Vsync sync signal released should be the starting point for drawing the view, systemically speaking.

When ScheduleTravesals is called, a message barrier is inserted into the MessageQueue to block other synchronous messages and allow asynchronous messages to enter. MChoreoGrapher then inserts a signal into MessageQueue to update the view, eventually leading to the doTraversals() method, which will first cancel the synchronization barrier and then execute performTraversals(). Obviously, the purpose of the message barrier is to increase the priority of peformTraversals and ensure that the view is drawn first.

It’s easy to see that the real starting point for rendering is the perfromTraversals() method:

The execution process of View.post

View. Post is implemented differently in different versions of Android. Before API24, the View. When ViewRootImpl is called, insert a Runnable directly into the mRunQueue of the ViewRootImpl, and then use performTraversals() to do so. View.post() is executed “at some point in the future” in the same order that view.post () was called, which means that in this series of Android versions, view.post is executed in the same order that view.post () was called itself

  1. Processing: Instead of executing the Runnable directly, the processing is inserted into the main thread’s MessageQueue.
  2. “Sometime in the future” means that perfromTraversals() inserts all runnables in the mRunQueue of the ViewRootImpl into the MessageQueue at some point in time. It must come after performTraversals().

As shown above, the next Message (here marked Runnable) cannot be executed until the entire perfromTraversals() body has been executed (included). In the perfromTraversals() body, The performMeasure(), performLayout(), and performDraw() methods are called sequentially. When these three methods are done, it means that the View has completed rendering. In this case, the view.post () execution must occur after the View is created.

In API24 and later, what view.post does has changed. When view.post () is called, the Runnable is inserted into the View’s respective mRunQueue. When performTraversals (), there is no unified handling, but according to performTraversals () – > dispatchAttachedToWindows () recursively calls to the child the View, The subview inserts its mRunQueue into the main thread’s MessageQueue, which means that in the higher version of execution, view.post () is executed in the order the views were iterated to.

What doesn’t change is that view.post () executes after the View is created, which is why it’s possible to call view.post () to get some data from the View on the screen.

Can handler.post () get width and height data like view.post ()?

The Activity exposes three commonly used lifecycle functions: onCreate(), onStart(), and onResume(). For example, onReumse() is executed at the end. We use Handler. Post () on the main thread to get data from a View.

    override fun onResume(){
        super.onResume()
        Handler(Looper.getMainLooper()).post{
            Log.d("getHeight",textView.height.toString())
        }
    }
Copy the code
  D/getHeight: 0
  
Copy the code

Apparently, it failed.

When a new Activity is created, the DecorView does not attach itself directly to the Activity. The DecorView is attached to the Activity in the handleResumeActivity(). But let’s be clear: If a View is not connected to the Activity, it will not receive synchronization signals from the system and will not be able to update (which makes no sense because it has nowhere to display it). If we look at the execution body of the handleResumeActiivty, we can see that the onResume() callback is used. If we insert a Message in onResume() to get the width and height of the rendered data, then the following Message is “queued” : The MessageQueue looks something like this:

What is currently executing is a yellow Message, which is a scheduling method issued from the H class of ActivityThread.java. It will call a series of methods in the handleResumeActivity, eventually going to onResume, If we use handle.post (), we can see that the Message is inserted after the yellow Message, but the A.DECOR = Decor has not yet been executed, and it is unlikely that the Decor has been drawn, which means there is no render, no view, and no data. The complete process is as follows:

end~