Android foundation - Handler message passing source code analysis

Handler source code analysis

Use the Android source code to understand the process of establishing relationships among the four members.
Android source code link

1. Create a Handler

·Handler constructor

insert image description here
·Callback (a method used to process Message, if there is no parameter, rewrite Handler's handleMessage method)
insert image description here
·In order to enable Handler to handle Message (handlerMessage method must be implemented):
1) Pass in to the constructor of Handler A Handler.Callback object, and implement the handleMessage method of Handler.Callback
2) No need to pass in the Handler.Callback object to the constructor of Handler, but you need to rewrite the handleMessage method of Handler itself
. Send a message to the message queue (sendMessage...)
call Sequence (the arrow indicates the calling direction):
Please add a picture description
post of sendMessage (the getPostMessage method is called)
Please add a picture description
getPostMessage method (a Runnable object is passed in, and a Message object is obtained)
insert image description here
In the getPostMessage method, a Message object is created and the incoming Runnable object Assign a value to the callback member field of the Message, then return the Message, and then pass the Message carrying the Runnable information into the sendMessageDelayed method in the post method.
That is to say, all postXXX methods need to be implemented internally with the help of the sendMessageXXX method. postXXX relies on sendMessageXXX, so the postXXX method can pass messages to the message queue through the sendMessageXXX method, but the messages passed to the message queue through the postXXX method all carry Runnable object(Message. callback).
·Relationship diagram of post... and sendMessage... methods
Please add a picture description
·You can see that all the methods in Handler that can directly or indirectly send Message to the message queue finally call the sendMessageAtTime method
Please add a picture description
enqueueMessage method:
Please add a picture description
====>Complete method call sequence
insert image description here

2. Create Looper

(Use the Looper.prepare() method)
· Looper's constructor
insert image description here
· Looper is used to cycle messages in threads. By default, when we create a new thread, there is no message queue MessageQueue in this thread. In order to enable a thread to bind a message queue, we need to use Looper: first we need to call Looper's prepare method, and then call Looper's Loop method.
insert image description here
Thread Thread and Looper are bound one-to-one, that is, there is at most one Looper object in a thread, and the constructor of <===>Looper is private, and the
current thread can only be obtained through the static method Looper.myLooper() The bound Looper.
· Save the reference to the current thread
insert image description here
In the Looper object, you can find the bound thread through sThreadLocal. There is a set method and a get method in ThreadLocal. You can store an object in ThreadLocal through the set method, and then you can take out the stored object through the get method.
ThreadLocal uses generics (the generic type is Looper) when it is new, that is, only the Looper object type can be written and read through the set and get methods of ThreadLocal. If the set method of ThreadLocal is called to pass in a Looper, it will The Looper is bound to the thread, and the corresponding get can obtain the Looper object bound to the thread.
Looper.prepare() method (to prepare Looper)
insert image description here
First, get the Looper object bound by thread sThreadLocal through sThreadLocal.get(). Since sThreadLocal is not bound to Looper in the initial situation, when the prepare method is called for the first time, sThreadLocal.get() returns null and will not throw abnormal.
------> Complete the two-way binding between sThreadLocal and Looper:
a. In Looper, you can get the thread bound by Looper through sThreadLocal;
b. Thread sThreadLocal can get the thread bound by sThreadLocal.get() method The Looper object.
After executing Looper.prepare(), we can get the Looper object bound by the current thread by calling Looper.myLooper() externally.
insert image description here
In a thread, Looper.prepare() can only be called once, because after the first call to Looper.prepare(), the current thread has bound Looper , and the second call to Looper.prepare( ) method, sThreadLocal.get() will return the Looper bound when prepare is called for the first time, not null, so the following code will throw new RuntimeException("Only one Looper may be created per thread") , thus throwing an exception, so a thread can only bind one Looper object.
====> After calling the Looper.prepare() method, the two-way binding between the current thread and the Looper is completed
. Call the **Looper.loop()** method to make the message queue circulate (in the thread bound by the Looper in execution)

3. Create a MessageQueue and bind the current thread

·Message queue: responsible for managing top-level program objects (Activity, BroadcastReceiver, etc.)
·enqueueMessage method (used to put a Message into the message queue)
·next method (blockingly removes a Message from the message queue)
·The message is added to When queuing, it will be inserted into the appropriate position in the queue according to the delay time, and the order of the queue is guaranteed to be sorted according to the delay time from the smallest arrival. It is convenient to directly obtain the queue head message when obtaining the message later.

4. Create Message (

A Message object is a thing that the thread needs to handle)

5.Handler sends and processes messages

Problem Summary

1. How the message sent by the handler arrives at the handlerMessage callback
can be seen in the handler source code. The sendMessage and post methods are called all the way down, and both call the sendMessageAtTime method. The sendMessageAtTime method calls the enqueueMessage method, and finally MessageQueue.enqueueMessage Put the message into the message queue;
you can see the next method in the source code of MessageQueue, which returns the message that has just been saved; you
can see in the Looper source code that the MessageQueue is instantiated in the constructor class, the queue.next method is called in the for loop of the loop, and if the Message is found, the msg.target will be executed; as you
can see in the Message class, this target is actually the Handler object, which is to call the
handlerMessage method of the Handler.
2. Where is Looper called?
The Looper of the main thread is actually initialized when the app is initialized and the Loop infinitely loops to get the Message. The specific code is in the main method of the ActivityThread, where prepareMainLooper initializes the Looper, and then calls the loop method.
3. How to ensure the uniqueness of Looper (multiple Loopers will not appear in one thread)?
In Looper's prepare, here is the initialization of Looper
insert image description here
It can be seen that the setting of Looper is not a simple set and get, but is operated through the ThreadLocal class. In the ThreadLocal class, the setting and acquisition of Looper need to pass in thread parameters. The only Looper means MessageQueue It is also unique, because MessageQueue is initialized once in the Looper construction method, but there can be multiple Handlers, because every time we initialize a Handler object, it will be recorded by Message, and finally call the handleMessage method of the corresponding Handler, and there will be no conflict .
4. How does the message delay?
Implemented in the for infinite loop, compare the delay time of each message. If the delay time of the current message is short, change the pointer to insert the current message into the queue. If the time to send the message is not up, then Not handed over to the looper: Looper will judge the time when receiving the message. If the time is not up, it will not return the message, which is equivalent to the message that needs to be sent before the principal and interest cycle arrives.
5. The producer-consumer mode
handler puts the message in the message queue, the looper fetches it from the message queue, and one produces and one consumes.

Guess you like

Origin blog.csdn.net/weixin_44901971/article/details/127560549