Android messaging is almost a must-ask topic in an interview, of course, not because of the interview, but to learn, more importantly, it is essential in the development of Android, occupy a pivotal position, so it is very necessary to understand it. So let’s talk about the basics.

Looper

Function:

1. Can Looper be instantiated directly?

The Looper constructor is private and does two things

 private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
    }
Copy the code

Can there be multiple Loppers per thread?

ThreadLocal ensures that a thread has only one Looper corresponding to it. A runtime exception is thrown.

private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() ! = null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); }Copy the code

3, Looper is an infinite loop, will it block?

Yes, when a loop is opened, it is an infinite loop, taking messages from MessageQueue and processing them, but it is also possible to exit the loop after there are no messages.

  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(); 
        if (msg == null) { 
            return;
        }
        msg.target.dispatchMessage(msg);
   }
   Copy the code

4. Can we call Looper.prepareMainLooper again?

PrepareMainLooper is the final call to prepare(), as in 2.

pre>
public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } }

5. When was MainLooper created?

MainLooper is created when the Activity is started to create an ActivityThread(not one Thread), so it cannot be created multiple times.

Public static void main(String[] args) {process.setargv0 (""); Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); If (sMainThreadHandler == null) {sMainThreadHandler = thread.gethandler (); } / / slightly stars. The loop (); throw new RuntimeException("Main thread loop unexpectedly exited"); }}Copy the code

Handler

Function:

How does Handler relate to Looper and MessageQueue?

We know that a Looper corresponds to a Thread, and a Looper contains a MessageQueue. When we create a Handler, we fetch the corresponding Looper from the current thread, and then we fetch the MessageQueue from the Looper.


public Handler(Callback callback, boolean async) {
    mLooper = Looper.myLooper(); 
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread that has not called            Looper.prepare()");
    }
    mQueue = mLooper.mQueue; 
    mCallback = callback;
    mAsynchronous = async;
    }
public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
    Copy the code

Message

Single necklace watch structure.

Function:

1. How are messages reused?

From the global message pool (linked list structure)

public static Message obtain() { synchronized (sPoolSync) { if (sPool ! = null) { Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag sPoolSize--; return m; } } return new Message(); }Copy the code

2. Why can Message be transmitted?

Android wants to pass objects either to implement Serializable or Parcelable, in this case the Parcelable interface.

Public final class Message implements Parcelable {//Copy the code

3. How to associate with Handler?

We know that the Handler acts as the “Courier” in the messaging mechanism, but how does it relate to the “cargo” –Message? Message actually has a member variable target which is of type Handler,

 Runnable callback;
public int arg1; 
public int arg2;
public Object obj;
 Handler target; 
 Copy the code

When we send a Message through a Handler, we end up assigning target to this, the current Handler.

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

Alternatively, if message.obtain (), the reused Message obtained will also be assigned a value.

By the way, handler.obtainMessage () calls message.obtain ().

public final Message obtainMessage(){
    return Message.obtain(this);
    }
Copy the code

Conclusion:

Through a series of inclusion relations, Looper, Handler, Message, and MessageQueue are eventually associated, thus forming a closed and open Message loop.