The original link

The Handler principle is the last article in this series. Handler plays an important role in the Android system, in cross-process communication, cross-thread communication and so on.

Other articles in the series

  1. Handler Message mechanism (1) Message reuse principle
  2. Handler message mechanism (2) ThreadLocal principle
  3. Handler Message mechanism (3) MessageQueue principle
  4. Handler Message mechanism (4) Looper principle

This article mainly analyzes the Handler from the following parts:

  • What is Handler?
  • How is Handler used?
  • Handler tools for the family of methods?

1. What is Handler?

Official description: A Handler allows you to send and process {@link Message} and Runnable objects associated with a thread’s {@link MessageQueue}. Each Handler instance is associated with a single thread and that thread’s message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it — from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue. The Handler can send and process Message and Runable objects associated with the thread. Each Handler instance is associated with a thread and the message queue for that thread. When a new Handler is created, it can be bound to a message queue on and under the thread that created the Handler. The Handler passes the message and Runable to the queue in the thread, and the message in the queue is read from the message.

The Handler is associated with the thread, sends a timed message or executable Runable object to the message queue within the thread, and processes the message.

2. How to use Handler?

Handler provides seven constructors, but only two of them actually build the Handler. The main difference between the two is that the constructor passes in the Looper association thread and the active getLooper to get the current thread’s Looper. Constructor of active Looper:

Public Handler(Callback Callback, Boolean async) {public Handler(Callback Callback, Boolean async) { The Handler created in the UI thread will eventually call mLooper = looper.mylooper (); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread " + Thread.currentThread() + " that has not called Looper.prepare()"); } mQueue = mlooper.mqueue; mCallback = callback; // Async flag, if true, incoming messages are async messages, default is false mAsynchronous = async; }Copy the code

The Looper constructor is passed as a parameter:

public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; MQueue = looper.mqueue; mCallback = callback; // Async flag, if true, incoming messages are async messages, default is false mAsynchronous = async; }Copy the code

Using Handler in UI thread:

Handler mHandler = new Handler(){ @Override public void handleMessage(@NonNull Message msg) { switch (msg.what) { case MSG_1: test1(); break; case MSG_2: test2(); break; default: super.handleMessage(msg); break; }}}; // Insert Message MSG = mhandler. obtainMessage(MSG_1); // other information about MSG... mHandler.sendMessage(msg);Copy the code

Simple way to use the above, very simple, I will not go into too much here.

3. Handler tools series methods?

3.1 obtain method

Within the obtain family of methods, a Message object is obtained using the message.obtain () method. I say obtain because the obtain method is a Message object that is reused. If there is a Message in the Message object pool, it is fetched directly from the pool, or if null, a new Message object is created. For details, please refer to Handler Message mechanism (I) Message reuse principle

3.2 Sending Messages

The Handler uses seven methods to send messages with the send prefix and five methods to send messages with the POST prefix. SendMessageAtTime method:

    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }
Copy the code

The enqueueMessage method is called directly inside the sendMessageAtTime method. PostAtTime method:

    public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
    {
        return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
    }
Copy the code

The postAtTime method wraps the Runable object as a message object and calls sendMessageAtTime, which also ends up in the enqueueMessage method. Here we look at the getPostMessage method, which obtains the Message object through message.obtain () and assigns r to the callback in the MSG.

    private static Message getPostMessage(Runnable r, Object token) {
        Message m = Message.obtain();
        m.obj = token;
        m.callback = r;
        return m;
    }
Copy the code

According to the above analysis, both the Send and POST series of methods end up calling enqueueMessage

private boolean enqueueMessage(MessageQueue queue, Message msg, Long uptimeMillis) {// Assign the Handler itself to target msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }Copy the code

In enqueueMessage approach, we see the MSG. Target assignment into a Handler object itself, in the message has been read, is through the MSG. Target. DispatchMessage are assigned to each message is processed. This is why multiple handlers on the same thread can process messages defined by the Handler itself. Next, the mAsynchronous variable, which is set when the Handler method is constructed, defaults to false. When this value is set to true, MSG will perform a setAsynchronous operation, which sets the message object to an asynchronous message. When analyzing MessageQueue, we know that asynchronous messages are preferentially processed when the queue has a synchronization barrier. Finally, messages are put into the MessageQueue queue through the enqueueMessage method of the queue. For information about MessageQueue, refer to the Handler message mechanism (3) MessageQueue principle.

3.3 removeMessage method

    public final void removeMessages(int what) {
        mQueue.removeMessages(this, what, null);
    }
Copy the code

Delete the messages logged in MessageQueue.

3.4 dispatchMessage method

Public void dispatchMessage(Message MSG) {// Callback is a Runable object if (MSG. = null) { handleCallback(msg); } else {// Handler constructor sets Callback, default is null if (mCallback! = null) { if (mCallback.handleMessage(msg)) { return; }} // empty method, user implementation handleMessage(MSG); }} private static void handleCallback(Message Message) {message.callback.run(); }Copy the code

Method, in which principle that a loop inside a piece of code “MSG. Target. DispatchMessage (MSG);” This code assigns the read message to the Handler object that handles the message. There are three main callback methods in the dispatchMessage method. This is how a specific message is assigned to the specified Handler. When messages are queued via POST, only interfaces implemented by Runable can be called back. When a message is queued by send, it can be processed in McAllback.handlermessage ()handleMessage().

Conclusion: Handler is a terminal processing module in the Handler mechanism, and also a message sending module. It is a module that we contact most frequently in the Handler mechanism. I hope that friends can have a clear understanding of the Handler message mechanism after reading this series of articles.