Handler principle of one person, one cat travel

If some time-consuming operations are performed in the main thread (also called the UI thread), ANR problems will occur. In order to avoid ANR, it is necessary to open a sub-thread to process time-consuming operations, such as network requests, database operations, and file reading operations.
How about updating the UI directly in the child thread after the time-consuming operation is completed?
Generally speaking, the following error occurs:

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
        at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6891)
        at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1048)
        at android.view.View.requestLayout(View.java:19781)
        at android.view.View.requestLayout(View.java:19781)
        at android.view.View.requestLayout(View.java:19781)
        at android.view.View.requestLayout(View.java:19781)
        at android.view.View.requestLayout(View.java:19781)
        at android.view.View.requestLayout(View.java:19781)
        at androidx.constraintlayout.widget.ConstraintLayout.requestLayout(ConstraintLayout.java:3172)
        at android.view.View.requestLayout(View.java:19781)
        at android.widget.TextView.checkForRelayout(TextView.java:7368)
        at android.widget.TextView.setText(TextView.java:4480)
        at android.widget.TextView.setText(TextView.java:4337)
        at android.widget.TextView.setText(TextView.java:4312)
        at icbc.agree.tmpapppp.MainActivity$2.run(MainActivity.java:37)

From the above code hint, it is not difficult to see that the UI can only be updated in the main thread, which is why the main thread is also called the UI thread.
But when we start a child thread in onCreate to change the text of a TextView, we will be surprised to find that the program can run normally. What is going on?
In fact, it is because the work of checking the thread is done by ViewRootImpl, but starting the child thread in onCreate may have been executed before the ViewRootImpl object is created. TextView's setText method, if you don’t believe it, you can sleep for a while before setText. what.

Since the UI cannot be updated in the child thread, we need a mechanism to notify the main thread to update the UI, which is the responsibility of the Handler!

How is Handler implemented?
To understand the principle of Handler, we need to know several concepts:
Message: The carrier of data passed and processed by Handler
Message Queue: Message queue
Looper: An iterator that constantly takes data from the message queue

Insert picture description here
The workflow of the Handler is roughly as shown in the figure above. The Handler sends a Message through methods such as sendMessage and puts it in the MessageQueue. Looper constantly takes out the data in the queue and distributes it.

Next, look at the working principle of Handler from the source code of the Android system:
First, let's look at the work in the main thread

public static void main(String[] args) {
        <-省略部分不相关代码->
        Looper.prepareMainLooper();

        <-省略部分不相关代码->

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

We see Looper.prepareMainLooper(); this line of code, you can go to Looper to see its function, in fact, it is the prepare method called, and its function is to create a message queue. The code is as follows:

		mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();

The last loop() in the main thread is called, now we look at the corresponding code:

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
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            <-省略代码部分->
            try {
                msg.target.dispatchMessage(msg);
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }

           <-省略代码部分->
        }
    }

Let's analyze the above code, we get the Message Queue, and then start an infinite loop, take out the Message through queue.next(), if the message is empty, it means that there is no message in the message queue, so stop the
last msg of the loop . target.dispatchMessage(msg); Should be familiar, right? This target is the Handler that sends the message.
Now let's take a look at the Handler part:
whether it is sendMessage or sendEmptyMessage, sendMessageAtTime is ultimately called, so we directly look at the source code part of sendMessageAtTime.

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);
    }

Continue to look down

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

Did you find the target? If you are interested, you can continue to look for the code, which is actually adding Message to the message queue.
So far, the complete process of Handler is sorted out!

Guess you like

Origin blog.csdn.net/RobinTan24/article/details/108795499
one
ONE