In most cases, the handleMessage resides on the same thread as the handler initializes, but the handler initializes by passing in a Looper object on the same thread as the handler.

1. Parameter-containing structurepublic Handler(Looper looper)

class MainActivity : AppCompatActivity() {
    var handler: Handler? = null
    var looper: Looper? = null
    override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        looper = Looper.getMainLooper()
        val thread = object : Thread() {
            override fun run(a) {
                super.run()
                Log.e("abc"."--- Runnable:threadName ---" + Thread.currentThread().name)
                handler = object : Handler(looper) {
                    override fun handleMessage(msg: Message?). {
                        super.handleMessage(msg)
                        Log.e("abc"."--- handleMessage:threadName ---" + Thread.currentThread().name
                        )
                    }
                }
            }
        }
        thread.start()
        myBtn.setOnClickListener {
            valmsg = Message() handler!! .sendMessage(msg) } } }// log the print status
--- Runnable:threadName ---Thread2 -
--- handleMessage:threadName ---main
Copy the code

The handler is initialized on Thread 2, and the handleMessage is initialized on Thread main.

2. No-parameter construction

If the construct is initialized using a Handler with no arguments, looper.prepare () and looper.loop () need to be called manually:

val thread = object : Thread() {
            override fun run(a) {
                super.run()
                Log.e("abc"."--- Runnable:threadName ---" + Thread.currentThread().name)
                Looper.prepare()
                handler = object : Handler() {
                    override fun handleMessage(msg: Message?). {
                        super.handleMessage(msg)
                        Log.e(
                            "abc"."--- handleMessage:threadName ---" + Thread.currentThread().name
                        )
                    }
                }
                Looper.loop()
            }
        }

// log the print status
--- Runnable:threadName ---Thread2 -
--- handleMessage:threadName ---Thread2 -
Copy the code

Not calling looper.prepare () manually raises an exception:

java.lang.RuntimeException: CanCreate handler inside thread thread [thread-2,5,main] that has not called Looper. Prepare ()Copy the code

Handler is used in the main thread: Most of the time we do not initialize and use handler in the child thread, but in the main thread. Prepare () and loop() are not required, because the main thread has a Looper(looper.getMainLooper ()).

3. How many loopers can a thread have? How are Handler and Looper related?

3.1 How many Loopers can a thread have

Looper.prepare()

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

Set (new Looper(quitAllowed)) :

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
Copy the code

Threadlocal is an internal storage class that can store data in a specified thread. Once the data is stored, only the specified thread can get the stored data. ThreadLocal ensures that each thread has its own Looper, meaning that a thread can only have one Looper. For details on ThreadLocal, see ThreadLocal

New Looper(quitAllowed) :

final MessageQueue mQueue;
final Thread mThread;
private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();

Copy the code

In the constructor, MessageQueue and the mThread attribute representing the current thread are initialized.

Calling looper.prepare () creates a separate Looper for the current thread using ThreadLocal, which contains a message queue

3.2 How are Handler and Looper related

A thread can have only one Looper, but a thread can create multiple handlers. How does a Looper correspond to multiple handlers? Looking at the source code, Post (Runnable R), postDelayed(Runnable R, Long delayMillis), postAtTime(Runnable R, Long uptimeMillis) and sendMessage both end up calling enqueueMessage 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

MSG. Target = this this is the target attribute that assigns the current Handler to the Message object, so that the MSG. Target can be used to distinguish different handlers when processing the Message.