What is a Handler

  • Handler allows you to send and process messages and Runnable objects associated with a thread MessageQueue. Each instance of Handler is associated with a thread MessageQueue. When you create a new Handler, It will be bound to the MessageQueue of the thread that created it, from which it can pass messages and Runnable objects to the MessageQueue and process the messages when they need to be executed.

The role of the Handler

Handler has two main uses:

  • Used to specify the point in time at which Message and Runnable will be executed (e.g., after a few seconds)
  • Used to place messages that other threads require this thread to execute in MessageQueue and execute them as needed (thread to thread communication)

Handler source code

  • There are two main objects during the operation of the Handler: a MessageQueue (MessageQueue) and a Looper (message loop). The former is used to store messages to be processed by the Handler, and the latter is taken out to the Handler when the MessageQueue has messages.

    Looper initializes with MessageQueue

    • Handler has seven constructors, but we only need to look at two of the main constructors:
 public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) = =0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        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;
        mAsynchronous = async;
    }
Copy the code
 /** * callback:handler handles the callback of a function ** async: whether it is an asynchronous message **/
 public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
Copy the code

The two main constructors of Handler are shown above, where we see the initialization of mLooper, one that gets the Looper instance via looper.mylooper, and the other that is passed in as an argument.

  • Looper. MyLooper gets the Looper instance of the current thread. Looper.prepare() is not called when Looper is empty, so there are two ways to create a Handler in a child thread. (The main thread already called looper.prepare () automatically when initialized, so there is no error if the main thread did not create Looper manually.)

    • Call the second constructor to pass in the Looper instance;
    • Call looper.perpare () to create an instance of Looper before calling the first constructor. Note that looper.loop () is also called after the handler is created for the handler to work properly;
  • MessageQueue is initialized by calling looper.mQueue(), and MessageQueue in looper is initialized when looper.perpare is called.

Handler message scheduling

  • The Handler can send messages in seven ways:

    • post(Runnable)
    • postAtTime(Runnable,long)
    • postDelayed(Runnable,long)
    • sendEmptyMessage(int)
    • sendMessage(Message)
    • sendMessageAtTime(Message,long)
    • sendMessageDelayed(Message,long)
  • Each of the seven methods above actually ends up calling the following methods

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
Copy the code

MessageQueue enQueue (Message,long); MessageQueue enQueue (Message,long); The message in the handler is now sent.

Handler Message processing

  • The looper. loop method keeps fetching messages from MessageQueue and calls Handler’s dispatchMessage(Message) method via message. target to hand the Message to Handler
     /** * Handle system messages here. */
    public void dispatchMessage(Message msg) {
        if(msg.callback ! =null) {
            handleCallback(msg);
        } else {
            if(mCallback ! =null) {
                if (mCallback.handleMessage(msg)) {
                    return; } } handleMessage(msg); }}Copy the code

If the Message is a Runnable Message, the Runnable run method is called. If the Message is a Runnable Message, the Runnable run method is called. If it is empty, the handleMessage method of the Handler is called to process the message. If it is not empty, the handleMessage of the CallBack is called to process the message, and the return value is used to determine whether to continue to call the handlerMessage of the Handler. At this point, the message processing process of Handler is complete.

conclusion

  • It can be seen from the above process that whether the Handler sends messages or receives MessageQueue is the same. Therefore, messages sent by the Handler in different threads are stored in the same memory. The looper.loop () method distributes messages to the Handler by calling Handler’s dispatchMessage in the thread where the Handler was created, enabling cross-thread delivery.

Which source