Efficient learning model
- What — — > according to — > how model
- What is? –> Why? –> How to use? –> Realization principle –> Summary and share (Learn to apply)
What is Handler?
- Handler is a mechanism provided by Android to communicate between threads
Why Handler?
UI thread model (Understood):
When an application is launched, the Android system starts a thread to execute the application, called the Main thread This Thread is responsible for handling all UI processing tasks, such as the use of all controls in the Android. widget and Android. view package.
If a time-consuming operation is added to the UI thread, the UI thread will be blocked and the user will feel “dead”. Therefore, a new thread must be opened to execute the time-consuming operation. However, Android provides that non-UI threads cannot access the UI, so Hanler is introduced to carry out inter-thread communication.
Android makes the following two provisions in this model:
1. Do not block the UI thread for more than 5s; otherwise, an ANR error will be reported.
2. Do not allow non-UI threads to access the UI; otherwise, an error will be reported.
Android is the use of a large number of message driven way to interact, such as the four major components Activity, Service, Broadcast, ContentProvider to start the process of interaction, cannot leave the message mechanism, Message mechanism involving the Handler/stars/MessageQueue/Message 4 classes;
UI threads are not thread-safe, why not make them thread-safe?
- UI has variability, even high frequency variability (as in games);
- The sensitivity of UI to response time requires that UI operations be efficient;
- UI components must be drawn in batches to ensure efficiency;
Main thread creation and brief code illustration: Understanding the UI thread working diagram from the production consumption model:
How to use Handler?
Handler Handler = new Handler(){@override public void handleMessage(final Message MSG){// Accept and process the Message}}; // sendMessage handler.sendMessage(message); handler.post(runnable);Copy the code
Instantiate a Handler and rewrite the handleMessage method, then call its Send and POST methods where they are used. It’s easy to use and supports delayed messages.
Four. Implementation principle
Schematic principle:
Code implementation principle:
Create Handler and associate Handler with Looper:
Public Handler(Callback Callback, Boolean async) {// Check whether the current thread has Looper mLooper = looper.myLooper (); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } //Looper holds a MessageQueue mQueue = mlooper.mqueue; }Copy the code
Implementation description:
-
Associate Handler with Looper. You must create Looper before creating Handler. Otherwise, an error will be reported. The Looper object can be obtained from looper.myLooper () because ActivityThread has created a Looper object from looper.prepareMainLooper () in main().
-
Looper will hold a MessageQueue;
-
A completed Handler should look like this:
class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; Looper.loop(); }}Copy the code
Looper provides the looper.prepare () method to create Looper and uses ThreadLocal to bind the current thread. Looper.loop() starts trying to retrieve messages from MessageQueue and distribute them to the corresponding Handler; That is, Handler’s association with threads is implemented by Looper.
2. Send a Message through send and POST, and add the Message to MessageQueue
Send messages through the send and post series methods, eventually went to the MessageQueue. EnqueueMessage (Message, long) method.
-
Message:
Message is an information carrier for communication between threads, containing some specific description and arbitrary additional data.
Message has setData() and getData() methods that fetch and add, respectively, data wrapped in Bundle objects that are passed between threads.
Message objects are not recommended to be obtained using New Message() and can be obtained using messa.obtain () or the obtainMassage() method of the Handler; Obtain () returns a Message object from the global Message Pool;
-
Message Pool: The Android system is dedicated to managing messages.
In order to avoid the overhead caused by the frequent creation and destruction of Message objects, we use a Message pool to maintain these objects. After the object is used, it can be re-used in the pool. Its size is 10.
-
MessageQueue:
MessageQueue is a queue of messages. It is a low-level class that contains messages distributed by Looper objects.
Messages are not added directly to the Message queue, but via the MessageQueue.IdleHandler object associated with Looper.
The looper.myQueue () method can be used to retrieve the message queue of the current thread; MessageQueue gets the Message via the next() method;
//MessageQueue Message next() { //... for (;;) { nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this) { //... Message msg = mMessages; / /... if (msg ! = null) { if (now < msg.when) { nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); } else { //... return msg; }} / /... }}Copy the code
MessageQueue
3. Fetch and distribute Message through looper.loop ()
Looper: A thread that runs a message loop. The thread itself has no message loop.
Call looper.prepare () to create the Looper object and then call looper.loop () to process the message.
Android automatically creates a Looper object for the main thread when it starts. Looper objects store messages and events through message queues. A thread can only have one Looper for each message queue.
By default, a Handler is bound to the Looper of the thread in which it is defined, or to the Looper of the UI thread.
Public static void loop() {final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; / /... for (;;) Message MSG = queue.next(); // might block // exit Looper if (MSG == null) {// No message indicates that the message queue is formspapers. Return; } / /... try { msg.target.dispatchMessage(msg); end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); } finally { //... } msg.recycleUnchecked(); Public void dispatchMessage(Message MSG) {if (MSG. Callback! = null) { handleCallback(msg); } else { if (mCallback ! = null) { if (mCallback.handleMessage(msg)) { return; } // Call handleMessage(MSG); }}Copy the code
Brief description:
-
Get the Looper object from myLooper(), because Looper holds MessageQueue, and then get the MessageQueue object;
-
An endless loop of calls to queue.next() to retrieve messages;
-
Dead loop by calling the MSG. Target. DispatchMessage (MSG) to distribute news news, MSG. The target is sending a message Handler;
-
DispatchMessage () calls handleMessage back to the UI thread to process the message;
Fifth, summarize and share
Core call stack flow: new Handler–>sendMessage()–>enqueueMessage()–>Looper.loop() –>queue.next()–>msg.target.dispatchMessage()–>handleMessage()
-
MyLooper () to retrieve the Looper object. The MessageQueue is stored in the Looper object.
-
Send and POST messages. Call enqueueMessage() to add messages to MessageQueue.
-
Retrieve and distribute messages via looper.loop () in an infinite loop;
-
Handle messages via hander.handleMessage;
Handler interview related questions:
-
How many handlers does a thread have? How many loopers are there in a thread? How to guarantee?
-
Handler memory leak cause? Why don’t other inner classes have this problem?
-
Why can the main thread use new Handler? What does the new Handler have to do if I want to do it in a child thread?
4. What is the Looper maintained in the child thread when there is no message in the message queue? What’s the use?
-
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?
-
How do you create a Message when you use it?
-
What happens to the message queue after using Handler’s postDelay?
-
How do non-UI threads update the UI?
-
Why does an infinite loop in the looper. loop method not result in ANR?