1 Meaning of Handler
- Similar to Ajax for Web development
- The difficulty of Android development is greatly reduced
- Multithreaded deadlock issues are rarely seen
Handler is the Android thread communication framework, completely solve the Android thread communication, thread switch problems. Handler design conforms to Demeter’s rule (least know principle), easy to use.
Thread communication implementation technical scheme: memory sharing.
2 Hadler’s Four elements
Hadler related classes:
-
Message: Obtain empty Message objects from the Message pool by message.obtain () to save resources and avoid memory jitter.
-
MessageQueue: Holds the Message, which belongs to the Looper object.
-
Looper(message loop) :
A Thread corresponds to a Looper object. To create a Handler, call looper.prepare (), execute the Looper constructor, initialize the message queue, and specify the current thread. Responsible for the entry and exit of messages.
-
Handler(message sending and processing) :
3 Handler source code analysis
The Handler workflow can be understood as a conveyor belt workflow:
Looper.loop opens the transfer and Thread powers it.
3.1 Handler
-
Message enqueue
Handler. Send — — > handler. EnequeueMessage — — > MessageQueue. EnquueuMessage
-
Looper.loop() — > messagequeue.next — >handler.dispatchMessage() — >handler.handleMessage
3.2 MessageQueue
Messages are obtained through new Message or obtain, which is essentially a piece of memory. Messages are passed between different threads, enabling memory sharing and thread switching.
Data structure: MessageQueue is a priority queue implemented by a singly linked list.
-
Singly linked list
Message has a next node.
Message->new(Message)->new(Message)…
-
priority
Message has a time attribute
MessageQueue. EnquueuMessage into the queue scheduling algorithm, insertion sort
-
The queue
First in first out
3.3 which source
A thread has only one looper
-
Looper.prepare:
Call the constructor to generate MessageQueue, get the current thread, bind looper to Thread, and set the Looper object to ThreadLocal.
-
Looper.loop
Looper.loop is an infinite loop that retrieves a Message from messageQueue and distributes it using a handler.
A loop can block in two ways:
1) Message wakes up automatically when the time is not reached
2) messageQueue is empty and waits indefinitely
Exit looper.quite to end the looper.loop() loop
4. Handler
-
How many handlers are there in a thread?
Multiple, you can create multiple handlers in a thread.
-
How many loopers are there in a thread? How to guarantee?
A thread has only one Looper.
Looper’s constructor is private. Looper. Prepare prepares a new Looper stored in ThreadLocal. If it is not null, discard the new Looper and set it to ThreadLocal. Get and set use the same ThreadLocal.
-
Handler memory leak cause? Why didn’t any of the other inner classes say there was a problem?
EnqueueMessage assigns handler to message.target, so Message holds handler, and handler holds the activity. When the activity is closed, if the message has not been processed, the memory occupied by the message has not been freed, meaning that the activity object is still held and therefore the activity memory cannot be freed.
-
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? The new Handler in the child thread calls looper. perpare and looper. loop. The main thread already calls this method in ActivityThread’s main function.
-
What is the Looper maintained in the child thread when there is no message in the message queue? What’s the use?
Call handler. GetLooper () quite (); When there is no message in the MessageQueue, the looper.loop() loop will always block at messagequeue.next’s nativePollOnce, and the thread resource cannot be freed. After calling quite, Messagequue. Next returns null, looper. Loop exits, the thread terminates, and thread resources are released.
The main thread calls quite and throws an exception.
-
Since there can be multiple handlers to add data to a MessageQueue (each Handler may be on a different thread when sending messages), how is it internally thread-safe?
MessageQueue stores and retrieves messages with synchronized lock. Synchronized locks the object of MessageQueue instance to ensure that a thread has only one place to operate the queue at the same time.
Synchronized: Built-in JVM lock that can be used for code blocks and methods
-
How should we create Message when we use it?
Message.obtain obtain empty Message objects from the Message pool to avoid memory jitter caused by multiple new messages being allocated and released (memory overcommitment mode).
-
Why does Looper loop death not cause apps to freeze? ANR: cannot respond to user input events within 5s or the BroadcastReceiver cannot end within 10s.
The user input event will be encapsulated as Message and processed by handler. If the event is not processed within 5 seconds, ANR notification will be sent through handler and a pop-up box will be displayed.
When the child thread finishes executing the code, the declaration cycle ends and the thread exits. The main thread cannot automatically terminate after running for a certain amount of time. The loop ensures that the main thread code can always be executed.
When there is no message in the main thread queue, the loop of looper.loop() will be blocked at the nativePollOnce of messagequeue.next. At this point, the main thread will release CPU resources and go to sleep until the next message arrives or a transaction occurs. Wake up the main thread by writing data to the pipe end.
The epoll mechanism adopted here is an IO multiplexing mechanism, which can monitor multiple descriptors at the same time. When a descriptor is ready (read or write ready), it immediately notifies the corresponding program to carry out read or write operations, which is essentially synchronous I/O, that is, read and write is blocked. Therefore, the main thread is dormant most of the time and does not consume a lot of CPU resources.
5 ThreadHandler
The run method creates a Looper object and calls looper.prepare and looper.loop(), essentially Thread+Looper. To facilitate the use of Handler in child threads, synchronization locks are added to initialize Looper and obtain Looper to ensure thread safety.
HandlerThread handlerThread = new HandlerThread("");
handlerThread.run();
new Handler(handlerThread.getLooper());
handlerThread.quit();
Copy the code
6 IntentService
A Service does not run in a separate thread, so it is not recommended to write time-consuming logic and operations in a Service, which will cause ANR. Time-consuming operations in a Service need to be performed by a separate thread.
IntentService
IntentService is the system pounds. We create a thread and provide a callback method, onHandlerIntent, in which time consuming operations can be performed.
IntentService creates the HandlerThread in the onCreate method, gets the Looper of the HandlerThread, and creates the Handler, which is executed in the child thread.
In the onStart method, the Handler sends a message, and the handleMessage calls the onHandlerIntent, overriding the onHandlerIntent to handle the business.
-
It can be used to execute time-consuming tasks in the background. After the tasks are executed, they are automatically stopped. In the Handler.handleMessage inside IntentService, calling onHandlerIntent calls stopSelf
-
It is suitable for high-priority background tasks and is not easy to be killed by the system. When creating child threads internally, the priority is 0.
-
It can be started multiple times, and each time-consuming operation is executed as a work queue in the onHandleIntent callback method of IntentService.