Android线程的消息队列

一、子线程创建Handler的前题条件是什么

  子线程创建Handler必须先创建子线程Looper。

  假如,在子线程不先创建Looper会怎样?

Thread {
    _handler = Handler()
}.start()

  结果:

E/AndroidRuntime: FATAL EXCEPTION: Thread-7
    Process: com.example.demoapp, PID: 8456
    java.lang.RuntimeException: Can't create handler inside thread Thread[Thread-7,5,main] that has not called Looper.prepare()
        at android.os.Handler.<init>(Handler.java:205)
        at android.os.Handler.<init>(Handler.java:118)
        at com.example.demoapp.MainActivity2.onCreate$lambda-0(MainActivity2.kt:17)
        at com.example.demoapp.MainActivity2.lambda$Qqlg1xygUvXBrkBzlVLkUUn-c9c(Unknown Source:0)
        at com.example.demoapp.-$$Lambda$MainActivity2$Qqlg1xygUvXBrkBzlVLkUUn-c9c.run(Unknown Source:2)
        at java.lang.Thread.run(Thread.java:764)

   原因,从Handler构造函数源码:

public Handler(@Nullable 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;
}

  创建Handler的线程没有创建Looper,调用Looper.prepare()就是抛出异常。Looper是Android提供线程间通信Handler最重要的组成部分,Handler发送的消息都需要Looper进行处理。

二、主线程Looper与子线程Looper区别

   主线程启动Looper调用Looper.prepareMainLooper()函数:

public static void main(String[] args) {
    ……
    Looper.prepareMainLooper();
    ……
}

  Looper.prepareMainLooper()函数实现:

/**
 * Initialize the current thread as a looper, marking it as an
 * application's main looper. See also: {@link #prepare()}
 *
 * @deprecated The main looper for your application is created by the Android environment,
 *   so you should never need to call this function yourself.
 */
@Deprecated
public static void prepareMainLooper() {
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();
    }
}

  子线程创建Looper调用prepare()函数:

/** Initialize the current thread as a looper.
 * This gives you a chance to create handlers that then reference
 * this looper, before actually starting the loop. Be sure to call
 * {@link #loop()} after calling this method, and end it by calling
 * {@link #quit()}.
*/
public static void prepare() {
    prepare(true);
}

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

  1. 主线程和子线程最终调用函数prepare(boolean quitAllowed),主线程调用prepare(false),Looper不允许退出,子线程调用prepare(true),Looper允许退出。

  2. 主线程Looper除了存储在sThreadLocal中,还赋值给了静态变量sMainLooper,通过getMainLooper()函数返回的就是这个静态变量。

/**
 * Returns the application's main looper, which lives in the main thread of the application.
 */
public static Looper getMainLooper() {
    synchronized (Looper.class) {
        return sMainLooper;
    }
}

三、消息队列是怎么创建的

  在调用prepare(boolean quitAllowed)函数时,创建Looper对象实例,在Looper构造函数中创建消息队列MessageQueue。

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

四、Looper与消息队列的关系

  

五、Hnadler延迟消息实现原理

  Handler中发送延迟消息函数sendMessageDelayed():

/**
 * Enqueue a message into the message queue after all pending messages
 * before (current time + delayMillis). You will receive it in
 * {@link #handleMessage}, in the thread attached to this handler.
 *  
 * @return Returns true if the message was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.  Note that a
 *         result of true does not mean the message will be processed -- if
 *         the looper is quit before the delivery time of the message
 *         occurs then the message will be dropped.
 */
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

/**
 * Enqueue a message into the message queue after all pending messages
 * before the absolute time (in milliseconds) <var>uptimeMillis</var>.
 * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
 * Time spent in deep sleep will add an additional delay to execution.
 * You will receive it in {@link #handleMessage}, in the thread attached
 * to this handler.
 * 
 * @param uptimeMillis The absolute time at which the message should be
 *         delivered, using the
 *         {@link android.os.SystemClock#uptimeMillis} time-base.
 *         
 * @return Returns true if the message was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.  Note that a
 *         result of true does not mean the message will be processed -- if
 *         the looper is quit before the delivery time of the message
 *         occurs then the message will be dropped.
 */
public boolean sendMessageAtTime(@NonNull 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);
}

 

  sendMessageDelayed()函数中调用sendMessageAtTime(, uptimeMillis)函数,参数uptimeMillis是消息添加的时间,消息队列是一个单向链表,按消息发送时间(ms)排序。发送延迟消息是当前时间+延迟时间,最后调用qnqueueMessage(queue, msg, uptimeMillis)函数向队列中添加消息。

private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
        long uptimeMillis) {
    msg.target = this;
    msg.workSourceUid = ThreadLocalWorkSource.getUid();

    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

  在Handler.enqueueMessage()函数中调用到MessageQueue.enqueueMessage()函数:

boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) {
        throw new IllegalArgumentException("Message must have a target.");
    }

    synchronized (this) {
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        if (mQuitting) {
            IllegalStateException e = new IllegalStateException(
                    msg.target + " sending message to a Handler on a dead thread");
            Log.w(TAG, e.getMessage(), e);
            msg.recycle();
            return false;
        }

        msg.markInUse();
        msg.when = when;
        Message p = mMessages;
        boolean needWake;
        // (1)
        if (p == null || when == 0 || when < p.when) {
            // New head, wake up the event queue if blocked.
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            // Inserted within the middle of the queue.  Usually we don't have to wake
            // up the event queue unless there is a barrier at the head of the queue
            // and the message is the earliest asynchronous message in the queue.
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            for (;;) {
                prev = p;
                p = p.next;
                if (p == null || when < p.when) {
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            msg.next = p; // invariant: p == prev.next
            prev.next = msg;
        }

        // (2)
        // We can assume mPtr != 0 because mQuitting is false.
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

  在enqueueMessage()函数中标识(1)的部分逻辑,when是消息添加时间,新消息添加时间是否是0或者添加小于当前队列头部消息时间,将新消息添加到队列头,当前新消息时间大于队列头消息,在队列中找到一个适合的位置添加消息。

  在Handler中发送延迟消息,消息是延迟处理,而非延迟添加。

六、线程间消息传递机制

  Looper.loop是消息循环重要的函数:

/**
 * Run the message queue in this thread. Be sure to call
 * {@link #quit()} to end the loop.
 */
public static void loop() {
    final Looper me = myLooper();
    me.mInLoop = true;
    final MessageQueue queue = me.mQueue;
    ……
    for (;;) {
        // (1)
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }
        ……
        try {
            // (2)
            msg.target.dispatchMessage(msg);
            if (observer != null) {
                observer.messageDispatched(token, msg);
            }
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } 
        ……
        msg.recycleUnchecked();
    }
}

 

  在Looper.loop()函数中做了两件事:

    • 从队列中获取将要处理的消息。
    • 消息分发。

  获取消息:

Message msg = queue.next(); // might block

    通过queue.next()函数获取要处理的消息。

@UnsupportedAppUsage
Message next() {
    // Return here if the message loop has already quit and been disposed.
    // This can happen if the application tries to restart a looper after quit
    // which is not supported.
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }

    int pendingIdleHandlerCount = -1; // -1 only during first iteration
    int nextPollTimeoutMillis = 0;
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }
        // (1)
        nativePollOnce(ptr, nextPollTimeoutMillis);

        synchronized (this) {
            // Try to retrieve the next message.  Return if found.
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            // (2)
            if (msg != null && msg.target == null) {
                // Stalled by a barrier.  Find the next asynchronous message in the queue.
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                if (now < msg.when) {
                    // Next message is not ready.  Set a timeout to wake up when it is ready.
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // Got a message.
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
                    return msg;
                }
            } else {
                // No more messages.
                nextPollTimeoutMillis = -1;
            }

            // Process the quit message now that all pending messages have been handled.
            if (mQuitting) {
                dispose();
                return null;
            }

            // If first time idle, then get the number of idlers to run.
            // Idle handles only run if the queue is empty or if the first message
            // in the queue (possibly a barrier) is due to be handled in the future.
            if (pendingIdleHandlerCount < 0
                    && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            if (pendingIdleHandlerCount <= 0) {
                // No idle handlers to run.  Loop and wait some more.
                mBlocked = true;
                continue;
            }

            if (mPendingIdleHandlers == null) {
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
            }
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }

        // Run the idle handlers.
        // We only ever reach this code block during the first iteration.
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            mPendingIdleHandlers[i] = null; // release the reference to the handler

            boolean keep = false;
            try {
                keep = idler.queueIdle();
            } catch (Throwable t) {
                Log.wtf(TAG, "IdleHandler threw exception", t);
            }

            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }

        // Reset the idle handler count to 0 so we do not run them again.
        pendingIdleHandlerCount = 0;

        // While calling an idle handler, a new message could have been delivered
        // so go back and look again for a pending message without waiting.
        nextPollTimeoutMillis = 0;
    }
}

    (1) nativePollOnce()函数,堵塞队列,等待有新消息加入队列,或者堵塞时间超时,检查队列是否有消息。nativePollOnce()函数是Native层函数:

      JNI层函数,android_os_MessageQueue_nativePollOnce():

static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
        jlong ptr, jint timeoutMillis) {
    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}

 

    Native层函数,NaitveMessageQueue.pollOnce()函数:

    源码:frameworks/base/core/jni/android_os_MessageQueue.cpp

class NativeMessageQueue : public MessageQueue, public LooperCallback {

}

class MessageQueue : public virtual RefBase {
    public:
        /* Gets the message queue's looper. */
        inline sp<Looper> getLooper() const {
            return mLooper;
        }
        ……
    protected:
        MessageQueue();
        virtual ~MessageQueue();

    protected:
        sp<Looper> mLooper;
};

     NativeMessageQueue继承自Native层的MessageQueue,Native层的MessageQueue中mLooper变量。

    (2) 在消息队列中获取消息。

  消息分发:

  分发消息通过msg.target.dispatchMessage(msg)函数,msg.target是发送消息的Handler对象。在Handler.dispatchMessage()函数:

/**
 * Handle system messages here.
 */
public void dispatchMessage(@NonNull Message msg) {
    // (1)
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        // (2)
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        // (3)
        handleMessage(msg);
    }
}

 

  (1) msg.callback != null,通过handleCallback()函数执行消息,msg.callback是Handler.post(runnable)的runnable函数体。Handler.post()函数将Runnable包装成一个Message,callback就是Runnable。

  Handler.post()函数实现:

/**
 * Causes the Runnable r to be added to the message queue.
 * The runnable will be run on the thread to which this handler is 
 * attached. 
 *  
 * @param r The Runnable that will be executed.
 * 
 * @return Returns true if the Runnable was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 */
public final boolean post(@NonNull Runnable r) {
    return  sendMessageDelayed(getPostMessage(r), 0);
}

private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

 

  m.callback = r,给runnable callback包装成Message结构。

  (2) mCallback != null,mCallback是Handler全局的Callback,在实例化Handler时传入的Callback。通过mCallback.handleMessage(msg),在Callback.handleMessage() == false,继续执行Handler类中重写的Handler.handleMessage()函数,这个函数前并消息清楚Message可能被修改了。通常Hook Handler的消息处理就是在这里,将Callback.handleMessage()的返回值设置false。当前返回值为ture处理消息后return。

  (3) Handler.handleMessage()函数

 

posted @ 2021-10-04 21:58  naray  阅读(923)  评论(0编辑  收藏  举报