The meaning of the Handler

Handler is not only unique to Android, but also has handlers in Spring, and Ajax in Web development is similar to the idea of Handler.

Handler makes Android development a lot easier. There are almost no multithreaded deadlocks in Android because Handler solves the communication between data for us.

Actually, Handler is not just for communication between threads. Communication between threads is a secondary function provided by Handler. The essence of Handler is a message management mechanism. It manages all the messages (things) on Android, and everything in Android will be encapsulated into messages (things) (such as clicking on the screen, displaying the page, refreshing the screen, etc.).

Or – All code in Android runs on Handler.

Communication between threads

The main communication between threads in Android is Handler, and the implementation of the Handler communication scheme is actually memory sharing scheme. Message is actually A piece of memory, and memory does not belong to threads. Memory is shared between threads. Thread A stores Message in A MessageQueue container, and thread B takes out Message (memory) in this container to realize communication between threads.

Interthread communication in Android also includes EventBus/RxBus, etc. In Java, the main method is wait/notify. This part of the Androuid handler has been required by the Linux layer encapsulation. Therefore, we do not need to wait/notify ourselves to implement communication between threads.

From creation to app launch

Boot from mobile phone

(At one point, I was asked what happened to the phone startup.) The Android system creates the first process, init, from the Native layer at startup. The init process then parses a local file called init.rc to create a Zygote process. Zygote’s job is to incubate processes. When the first process is incubated, the SystemServer process takes a back seat and waits through the Socket for the call to create the process.

The SystemServer process is one of the core of the Android system, most of the Android services are provided in this process, SystemServer running processes have more than 60 public, mainly including: ActivityManagerService(AMS), WindowManagerService(WMS), PackagManagerService(PMS), etc. These system services exist as a single thread in the Systemserver process.

Start -> Zygote -> SystemServer ->(AMS)/ (WMS)/(PMS)...

Click on the desktop app icon

1. The desktop of the mobile phone is actually an app called Lancher, so clicking the app icon is equivalent to clicking a button in the activity. 4.Zygote creates the application and assigns it a JVM. 5. To start a Java program, start a main () function. The main() function is activityThread.main ()

Click the desktop icon (Binder IPC)-> AMS -> Zygote -> JVM -> ActivityThread.main()

Added: why assign a JVM to each application, because each app is independent, one collapse does not affect the other, easy management, isolation, etc.

App startup – ActivityThread.main()

PrepareMainLooper (); prepareMainLooper(); And stars. Loop (); Create Looper and start it. So all the code in Android is run on the Handler, including the system, write their own

The structure of the Handler

Handler looks something like this.

Each Thread has a variable inside the ThreadLocalMap,

ThreadLocal stores a Looper,

Looper has a unique MessageQueue,

MessageQueue is a single-list implementation priority queue that holds the Message list

The principle of the Handler

Carries goods like a conveyor belt.

handler.sendMessage(message); Keep sending messages to the conveyor belt

Just plug in the Looper (Looper.loop) and the conveyor starts

At the end of the belt,handler.dispatchMessage () continually picks up messages

Handler source code

The use of the Handler

Sending messages: in the thread handler.sendMessage(message); Receive message: new Handler, and then, in the anonymous inner class, override the method handleMessage to receive message.

In the receiving area, the new Handler is actually going to bind the Handler to the Looper, which is used directly in the main thread because it’s done in activityThread.main (). Looper.prepare(), looper.loop ();

Start sending messages from sendMessage

What is known now: Sending messages: handler -> sendMessage () ->…. Receiving messages:… – > handler. HandleMessage ()

  1. There are many ways to send a message, sendMessage/ POST, etc., but it all ends up in sendMessageAtTime

  1. Handler. EnqueueMessage again will be transferred to the messasgeQueue. EnqueueMessage.

  1. Point!! MessasgeQueue enqueueMessage this way is to put a message into the message queue, that’s where the real sending messages

Easy to understand:

Message queue – Priority queue for a singly linked list implementation

MessasgeQueue data structure: Priority queue for a single linked list implementation

Message queues are structured like this:

MessageQueue stores a Message

Message has a next of type Message

So conclusion: there is a Message (mMessages) in MessageQueue, and there is a Message1 in the next of mMessages, there is a next in Message1, there is a Message2 in the next…

So here it is: Messge- “next-” Message – “next (Message)…

A priority is a Message execution time. Each Message contains when the Message should be executed. When creating a Message, you can set the execution time, and when inserting a Message into the queue, it will be inserted into the Message queue according to the execution time.

So this is the code that we had before for (;;) If the next node is empty (tail) or the next node’s time > my time, break; (Insert MSG into this position)

Receive the handleMessage

Now known: send a message: handler – > sendMessage () – > messasgeQueue. EnqueueMessage receives the message:… – > handler. HandleMessage ()

  1. The starting point for receiving messages is in Looper. Loop. Power on the conveyor belt and cycle the message wirelessly

  1. Point!! MessasgeQueue. Next () in front of the corresponding messasgeQueue. EnqueueMessage message, this is a message in the message queue

Supplement:

So to exit the looper loop, the only way to stop the handler is MSG =null

The only way to make MSG =null is to make McOntract =true

The only way to get mquit =true is messasgequeue.quit

  1. Handler. DispatchMessage () send a MSG

The code that sends the message in looper. loopmsg.target.dispatchMessage(msg);

The msg.target is the Handler

In the handler. SendMessage (message); Handler. EnqueueMessage, where MSG. Target = this; Assigns itself to MSG, so every message has a reference to handler, which again causes a memory leak

  1. DispatchMessage is always called to handleMessage, which is your own implementation

Summarize the invocation process

Send the message handler – > sendMessage () – > messasgeQueue. EnqueueMessage receive messages: Looper.loop ()-> messasgequeue.next ()-> handler.dispatchMessage()- > handler.handleMessage ()

Detailed explanation of each part

Message

Message can be thought of as a block of memory. The handler mechanism implements communication between threads by sharing this block of memory.

Message is a single-list implementation of a priority queue with one Message in it, one Message in it, and so on. The priority is determined by the order of the Message, which is determined by the long WHEN stored in the Message, which represents the time when the Message is executed.

The Message of the creation

  1. Direct new, but infinite new will explode memory
  2. Message.obtain()It is recommended to use

Cached pool: The MSG cached pool is used to empty data and put it into the cache pool instead of destroying it when the MSG is ready to recycle. This operation is actually very common in Android, such as RecyclerView level 4 cache pool, is also empty itemView and reuse, not destroy in new. Glide and so on. Benefits: KNOWLEDGE of the JVM: The JVM uses a tag collection algorithm. If the JVM keeps creating and collecting, memory fragmentation becomes severe, resulting in less and less complete memory, resulting in frequent GC and memory jitter.

The destruction of the Message

The cache pool here does the same thing as Message Next, except that the pool is empty of Messages.

MessageQueue

Although the handler mechanism is a perpetual motion machine, it can still block and hibernate.

For example, when.next doesn’t get a message, or when the execution time is not up

Quit the only way to stop the perpetual motion machine, it says above

Synchronization barrier

The handler mechanism is used not only for us, but for the entire system. Message lists are all queued there. When an urgent event needs to be dealt with, they have to jump the queue for execution, just like an ambulance on the road, and other cars have to give up their seats. This is the synchronization barrier.



Specific code:Setting synchronization Barriers

Some urgent events in the system run first. For example, if you refresh the UI, the screen refresh rate at 60 Hz is 60 times per second, which is 1/60=16.67ms.

Looper

Initialize the

To ensure that a thread can have only one Looper, a Looper cannot be arbitrarily new, so its constructor is private

Looper can only be initialized with looper. prepare

Because MessageQueue is final, it can only be assigned once

ThreadLocal

Sthreadlocal.get () = sthreadLocal.get ()

The sThreadLocal is static final, meaning there is only one sThreadLocal per thread and it cannot be changed after assignment.

For more information on ThreadLocal, see the previous article: juejin.cn/post/695650…

So let’s just say that in ThreadLocal we have a ThreadLocalMap and in ThreadLocalMap we have an internal class Entry and the Entry array holds key-value pairs of

and the key is ThreadLocal and the value is the value stored, Is the stars
,value>

Each Thread has a global variable called ThreadLocalMap, which holds context variables and other values (such as looper today).

So a unique sThreadLocal creates a unique Looper.(prepare sThreadLocal. The get ()! Sthreadlocal. set(new Looper(quitAllowed)). The only Looper makes the only MessageQueue(In the private constructor Looper new, final of MessageQueue)Many reasons cause a thread to have only one Looper and MessageQueue

The interview questions

1: How many handlers are there in a thread?

Zillions of them, whatever new you want, but there’s only one Handler mechanism

2: How many Looper are there in a thread? How to guarantee?

A looper, see looper initialization above

3: Handler memory leakage causes? Why didn’t any of the other inner classes say there was a problem?

Handler new is yellow

translation

Because this direct new out of the anonymous inner class, and the inner class if to access external objects, methods. This is automatically added.

Since the Handler and Activity life cycles are different, this can cause memory leaks.

Reasons for different life cycles: Message can be set to be executed after 20 minutes. And in the handler. SendMessage (); Handler will be given to MSG to hold

Message holds -> Handler holds -> Activity. This leaks memory

4: Why can the main thread use new Handler? What does the new Handler have to do if I want to prepare it in a child thread?

In the stars. Prepare (); Looper.loop(); Middle new, look up here. It is best to use HandlerThread directly

5: The Looper maintained in the child thread, what is the processing scheme when there is no message in the message queue? What’s the use?

You must messagequeue.quit, see above

6: Since there can be multiple handlers to add data to MessageQueue (each Handler may be in a different thread when sending messages), how does it ensure thread safety internally?

Lock, MessageQueue add messages are locked

7: How should we create Message when we use it?

Message. Obtain (see above)

8: Why does Looper loop death not cause applications to freeze

This is actually an unrelated topic. The ANR is stuck and blinks. For example, if the message is not processed for 5s or broadcast for 10s, the ANR is stuck and blinks. But even the ANR flash back message is passed by Handler.