After the interview

Interviewer: You have read the source code of Handler mechanism on your resume. How to improve the priority of Message?


In internal analysis:

First, we analyze that the Message is sent by Handler and then added to The MessageQueue. Looper iterates through the MessageQueue to obtain the Message for execution.

MessageQueue is sorted by time. If you want to increase the priority of Message, you need to place Message before MessageQueue, so that the execution will be prioritized.

The most common ways to send a Message are:

  • sendMessage
  • sendEmptyMessage
  • post
  • sendMessageDelayed
  • sendEmptyMessageDelayed
  • postDelayed

The first three have no delay, and the last three can add delay. Since the first three have no latency, they are generally placed before MessageQueue.

The question is so simple.


A: Sending messages using sendMessage, sendEmptyMessage, and POST puts Message before MessageQueue, so using these three methods can increase the priority of Message.


Interviewer: No.


Although know oneself interview kneel, but still want to take the following mood research, in the end is where the problem?

Reanalyze the process

First, we need to make sure that messages are actually sorted by time in MessageQueue.

MessageQueue insert Message: enqueueMessage(Message MSG, long WHEN), when is actually the delay time.

boolean enqueueMessage(Message msg, long when) { ... synchronized (this) { ... msg.when = when; Message p = mMessages; . if (...) {... } else { ... Message prev; // Sort MessageQueue from smallest to largest for (;;) { prev = p; p = p.next; if (p == null || when < p.when) { break; }... } msg.next = p; // invariant: p == prev.next prev.next = msg; }... } return true; }Copy the code

Let’s look at when for sendMessage(Message MSG) :

    public final boolean sendMessage(Message msg){
        return sendMessageDelayed(msg, 0);
    }
Copy the code

SendMessage actually calls the sendMessageDelayed method inside, and the delay time is 0.

    public final boolean sendMessageDelayed(Message msg, long delayMillis){
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
Copy the code

SendMessageDelayed internally calls the sendMessageAtTime method, where the time is systemclock.uptimemillis () + delay time, i.e. Systemclock.uptimemillis () + 0.

    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

EnqueueMessage was called internally in sendMessageAtTime.

    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

EnqueueMessage calls Queue. enqueueMessage, which is the MessageQueue method we initially analyzed to insert Message.

When sendMessage(Message MSG) is not 0, but systemclock.uptimemillis () + 0.

Systemclock. uptimeMillis() represents the total amount of time since the system was started, in milliseconds.

em…

Is there a way to change when to 0. In this case, the sent Message must precede the MessageQueue because 0 is the smallest. (Of course, you can’t have negative numbers, right? 😂)

To find the answer

Let’s look at how the Handler sends a Message:

Huh? This method has not been seen before:

    public final boolean sendMessageAtFrontOfQueue(Message msg) {
        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, 0);
    }
Copy the code

Is enqueueMessage sendMessageAtFrontOfQueue internal call.

    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

What? UptimeMillis is 0!! Isn’t that what we want?

Calm down, send and POST correspond, so post should also have a method like this:

    public final boolean postAtFrontOfQueue(Runnable r){
        return sendMessageAtFrontOfQueue(getPostMessage(r));
    }
Copy the code

Well, the results are in!!

Messages can be prioritized using the following methods:

  • sendMessageAtFrontOfQueue
  • postAtFrontOfQueue

New knowledge, GET!

Guess you like

  • Make an App that never crashes
  • Custom Gradle Plugin+ bytecode staking
  • From handwritten ButterKnife to mastering annotations, AnnotationProcessor
  • Here, I want you to write a performance check