Android中Handler的消息机制分析(一)

小二玩编程

ps:阅读原文可获取 demo 源码,文章末尾有原文链接

ps:源码是基于 android api 27 来分析的,demo 是用 kotlin 语言写的。

Handler 是 Android 线程之间的消息机制,主要的作用是将一个任务切换到指定的线程中去执行,与 Handler 一起协同工作的有 Looper、Message 和 MessageQueue;下面我们以 Handler 在主线程处理消息为例,对 Handler 发送消息(本质上是将消息插入链表)和处理消息(顺便将消息移除链表)相关的源码进行分析。

我们看一下 ActivityThread 中的 main 方法;

public static void main(String[] args) {

    ......
    //1、
    Looper.prepareMainLooper();
    ......
    //2、
    Looper.loop();
    ......

}

注释1 其实它内部是初始化 Looper 和 MessageQueue,我们点击注释1 相关的代码看看;

public static void prepareMainLooper() {

    //3、
    prepare(false);
    ......

}

我们点击进去看看注释3 中的代码,也就是 Looper 的 prepare 方法;

private static void prepare(boolean quitAllowed) {

    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    
    //4、
    sThreadLocal.set(new Looper(quitAllowed));

}

从 Looper 的 prepare 方法看出,一个线程中只能实例化一个 Looper,也就是只能有一个 Looper 并将 Looper 保存到 ThreadLocal 类型的变量中;ThreadLocal 的作用是使同一变量在每一个线程中有各自的副本,每个线程用同一个 ThreadLocal 对象保存的数据是不共享的;我们看看注释4 中 Looper 的构造方法;

private Looper(boolean quitAllowed) {

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

}

从 Looper 的构造方法可以看出,这里顺便实例化了一个 MessageQueue 对象;我们假设在子线程中发送一条消息,用什么语句好呢?我们就用 Handler.sendEmptyMessage 语句吧,看看 Handler 的 sendEmptyMessage 方法;

public final boolean sendEmptyMessage(int what)
{

    return sendEmptyMessageDelayed(what, 0);

}

sendEmptyMessage 方法调用了 Handler 的 sendEmptyMessageDelayed 方法,我们看看 sendEmptyMessageDelayed 方法;

public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {

    Message msg = Message.obtain();
    msg.what = what;
    return sendMessageDelayed(msg, delayMillis);

}

sendEmptyMessageDelayed 方法里创建了一个 Message 对象,并调用了 Handler 的 sendMessageDelayed 方法,我们往下看 sendMessageDelayed 方法;

public final boolean sendMessageDelayed(Message msg, long delayMillis)
{

    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);

}

这里的 SystemClock.uptimeMillis() 语句表示系统的开机时间,sendMessageDelayed 方法调用了 Handler 的 sendMessageAtTime 方法,sendMessageAtTime 方法又调用了 Handler 的 enqueueMessage 方法,Handler 的 enqueueMessage 方法最终调用了 MessageQueue 的 enqueueMessage 方法,我们且看 MessageQueue 的 enqueueMessage 方法;

boolean enqueueMessage(Message msg, long when) {

    ......
    synchronized (this) {
        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;

        //5、
        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.
            //6、
            needWake = mBlocked && p.target == null && msg.isAsynchronous();

            //7、
            Message prev;
            for (;;) {
                prev = p;
                p = p.next;
                if (p == null || when < p.when) {
                    break;
                }

                //8、
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            msg.next = p; // invariant: p == prev.next
            prev.next = msg;
        }

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

}

注释5 表示队列为空或者当前消息不是延迟消息又或者当前消息执行时间小于队头消息执行时间;注释6 中的 p.target == null && msg.isAsynchronous() 表示为这个消息是系统消息;注释7 表示根据这个消息的执行时间去将这个消息插入到适当的位置;注释8 表示如果队列中有系统消息,就不需要唤醒;注释9 表示需要的情况下唤醒取消息线程,也就是唤醒 Looper.loop 方法所在的线程;MessageQueue 的 enqueueMessage 方法最终完成消息的插入。

在 ActivityThread 的 main 方法注释1 中可以看到 Looper 的初始化是在主线程中进行的,注释2 中的 Looper.loop 方法也是在主线程进行调用的,当我们在 Activity 中直接初始化一个 Handler 时,Handler 的初始化也是在主线程执行的,这就说明了 Handler 处理消息的线程和 Handler 持有 Looper 的初始化时所在的线程是同一线程,什么意思呢?也就是创建 Looper 对象的线程和 Handler 处理消息的线程是同一线程。

我们看一下 ActivityThread 的 main 方法中注释2 的代码;

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;

    // Make sure the identity of this thread is that of the local process,
    // and keep track of what that identity token actually is.
    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();

    for (;;) {
        //10、
        Message msg = queue.next(); // might block
        ......
        try {
            //11、
            msg.target.dispatchMessage(msg);
            ......
        } finally {
            ......
        }
        ......
        //12、
        msg.recycleUnchecked();
    }

}

注释10 的代码最终是获取消息,我们看一下注释10 的具体实现,也就是 MessageQueue 的 next 方法;

Message next() {

    ......
    int nextPollTimeoutMillis = 0;
    for (;;) {
        ......
        //13、
        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;
            ......
            if (msg != null) {
                if (now < msg.when) {
                    //14、
                    // 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.
                    //15、
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    //16、
                    msg.next = null;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
                    return msg;
                }
            } else {
                // No more messages.
                //17、
                nextPollTimeoutMillis = -1;
            }
            ......
        }
        ......
    }

}

注释13 表示线程阻塞;注释14 表示队头消息没到执行时间,那么就休眠nextPollTimeoutMillis;注释15 表示得到一个需要立即执行的消息;注释16 表示将链表中的消息进行移除;注释17 表示队列中没有消息了,那么就进入无限期休眠;MessageQueue 的 next 方法最终获取一个消息并从链表中移除消息。

我们看 Looper 中 loop 方法的注释12,它表示对 Message 对象进行回收,我们要发送消息的 Message 对象,尽量不要 new Message() 创建一个,最好的方式是通过 Message.obtain() 获取,它每次都会从可回收的对象池(以链表的形式)中获取一个 Message 对象,如果有的话,这样就避免了对象的创建,降低了内存的开销。

我们看看注释11 它是消息的处理过程,msg.target 其实是一个 Handler,也就是我们发送消息的那个 Handler,如何证明呢?发送消息的过程中会调用 Handler 的 enqueueMessage 方法,我们看看 enqueueMessage 方法;

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {

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

}

这会可以证明 msg.target 就是发送消息的 Handler 了吧,我们看一下 Handler 的 dispatchMessage 方法;

public void dispatchMessage(Message msg) {

    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }

}

从 Handler 的 dispatchMessage 方法可以看出,处理消息的方式有3种,第一种是 msg.callback,它表示一个 Runnable 接口,不需要重写 Handler 的 handleMessage 方法;第二种是 mCallback,它表示 Callback 接口,不需要重写 Handler 的 handleMessage 方法;第三种是 Handler,需要重写 handleMessage 方法;3种处理消息的优先级从大到小排列为:Runnable > Callback > Handler。

下面对这3种处理消息的方式进行举例:

1)Runnable 接口处理方式:

class MyR1: Runnable {

    override fun run() {
        Log.d("MainActivity","MyR1所在当前线程为:" + Thread.currentThread().name)
    }

}

mH1!!.post(MyR1())

2)Callback接口处理方式:

class MyCallback: Handler.Callback {

    override fun handleMessage(msg: Message?): Boolean {
        Log.d("MainActivity","MyCallback所在当前线程为:" + Thread.currentThread().name)
        return true
    }

}

mH2 = Handler(MyCallback())

3)Handler 子类处理方式:

class MyHandler: Handler() {

    override fun handleMessage(msg: Message?) {
        super.handleMessage(msg)
        Log.d("MainActivity","MyHandler所在当前线程为:" + Thread.currentThread().name)
    }

}

mH3 = MyHandler()

从本篇文章分析的过程中,Handler 的消息发送过程是这样的:

Handler.sendEmptyMessage -> Handler.sendEmptyMessageDelayed -> Handler.sendMessageDelayed -> Handler.sendMessageAtTime -> Handler.enqueueMessage -> MessageQueue.enqueueMessage -> 消息插入链表

Looper 的 loop 方法处理消息的过程是这样的:

Looper.loop -> MessageQueue.next -> 链表中取出消息 -> Handler.dispatchMessage(Runnable接口处理方式、Callback接口处理方式、Handler子类处理方式)

阅读 98

活到老,学到老。

1 声望
1 粉丝
0 条评论
你知道吗?

活到老,学到老。

1 声望
1 粉丝
宣传栏