文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

详解Android消息机制完整的执行流程

2022-11-13 18:14

关注

从Handler.post()说起

Handler.post()是用来发送消息的,我们看下Handler源码的处理:

public final boolean post(@NonNull Runnable r) {
   return sendMessageDelayed(getPostMessage(r), 0);
}

首先会调用到getPostMessage()方法将Runnable封装成一条Message,然后紧接着调用sendMessageDelayed()方法:

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

这里我们介绍下sendMessageDelayed()的第二个参数delayMillis,这个表示消息延时执行的时间,而post()方法本身代表着非延迟执行,所以这里delayMillis的值为0.

而如果是我们另一个常用的函数postDelay(),这里的delayMillis的值就是传入的延迟执行的时间

继续往下走,会调用到Handler.sendMessageAtTime()方法:

public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;
    //...
    return enqueueMessage(queue, msg, uptimeMillis);
}

获取到Looper对应的消息队列MessageQueue,继续往下走,作为参数传给enqueueMessage()方法,这个方法主要是对上面封装的Message进行填充:

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

比如将Message被负责分发的target赋值成当前Handler对象,然后根据是否为异步Handler来决定是否给Message添加异步标识。

MessageQueue.enqueueMessage()添加消息至队列中

boolean enqueueMessage(Message msg, long when) {
    //...
    synchronized (this) {
        //...
        msg.markInUse();
        msg.when = when;
        Message p = mMessages;
        boolean needWake;
        //1.
        if (p == null || when == 0 || when < p.when) {
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            //2.
            for (;;) {
                prev = p;
                p = p.next;
                if (p == null || when < p.when) {
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            msg.next = p;
            prev.next = msg;
        }
        //3.
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

这个方法的使用很明确,就是将Message添加到消息队列中,下来我们主要讲解这个方法的三个核心点,对应上面的注释标识:

1.如果当前消息队列本来为null、消息执行的时间戳为0、消息执行的时间小于消息队列队头消息的执行时间,只要满足上面三个条件之一,直接将该条Message添加到消息队列队头;

这里说下消息执行的时间戳什么时候会为0,就是调用Handler.sendMessageAtFrontOfQueue()这个方法,就会触发将当前发送的Message添加到消息队列队头。

2.如果上面的三个条件都不满足,就遍历消息队列,比较将要发送的消息和消息队列的消息执行时间戳when,选择适当的位置插入;

3.判断是否需要唤醒当前主线程,开始从消息队列获取消息进行执行;

Looper.loop()分发消息

这个方法会开启一个for(;;)循环,不断的从消息队列中获取消息分发执行,没有消息时会阻塞主线程进行休眠,让出CPU执行权。

for(;;)循环会不断的调用Looper.loopOnce(),开始真正的消息获取和分发执行:

private static boolean loopOnce(final Looper me,
        final long ident, final int thresholdOverride) {
    Message msg = me.mQueue.next(); // might block
    if (msg == null) {
        return false;
    }
    try {
        msg.target.dispatchMessage(msg);
    }
    msg.recycleUnchecked();
    return true;
}

上面是经过简化的代码,首先调用MessageQueue.next()从消息队列中获取消息,然后调用关键方法msg.target.dispatchMessage(msg)开始消息的分发执行,这个方法之前的文章有进行介绍,这里就不再过多介绍了。

接下来我们看下MessageQueue.next()如何获取消息的。

MessageQueue.next()获取消息

Message next() {
    //...
    for (;;) {
        //1.休眠主线程
        nativePollOnce(ptr, nextPollTimeoutMillis);
        synchronized (this) {
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            //2.获取异步消息
            if (msg != null && msg.target == null) {
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            //3.获取普通消息
            if (msg != null) {
                if (now < msg.when) {
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    msg.markInUse();
                    return msg;
                }
            } else {
                nextPollTimeoutMillis = -1;
            }
            
            //...
            if (mPendingIdleHandlers == null) {
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
            }
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }
        //4.执行Idle消息
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            mPendingIdleHandlers[i] = null;

            boolean keep = idler.queueIdle();
            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }
        //...
    }
}

总结

本篇文章主要是详细分析了Android消息机制的整个执行流程(不包括native层),最核心的就是HandlerLooperMessageQueueMessage四个类及构成的关联。

到此这篇关于详解Android消息机制完整的执行流程的文章就介绍到这了,更多相关Android消息机制内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯