结合源码拆解Handler机制,字节HarmonyOS鸿蒙高级岗

打印 上一主题 下一主题

主题 848|帖子 848|积分 2544

先自我先容一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索发展,但自己不成体系的自学结果低效又漫长,而且极易遇到天花板技能故步自封!
因此收集整理了一份《2024年最新HarmonyOS鸿蒙全套学习资料》,初志也很简单,就是希望可以或许资助到想自学提升又不知道该从何学起的朋侪。





既有适合小白学习的零根本资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开辟知识点,真正体系化!
由于文件比力多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码课本、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你必要这些资料,可以添加V获取:vip204888 (备注鸿蒙)

正文

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);
}
可以看到,在这里创建了MessageQueue对象,也就是我们常说的Handler机制里的四大元素之一队列,然后把发送的消息和队列以及时间参数传到了enqueueMessage()方法,也就是入队列操作:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
继承来看queue的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;
}

在分析这个方法前,先来想一想队列这个概念,可能有部分人对它有点生疏,这里解释一下,MessageQueue是一个队列,它并不是数组或者聚集那样,是界说一个有容量的“容器”,而是通过单链表Message这个结构:
public final class MessageQueue {
private static final String TAG = “MessageQueue”;
private static final boolean DEBUG = false;
// True if the message queue can be quit.
private final boolean mQuitAllowed;
@SuppressWarnings(“unused”)
private long mPtr; // used by native code
Message mMessages;//单链表Message

作为MessageQueue持有的变量,Message里有一个指向下一个Message对象的引用,因此Message消息其实是一个单链表情势串联在一起的。它差别于线性表那样,比如一个数组是一块一连的内存空间,里面每一个对象按照序次排在一起,因此查询的时间可以通过基址加偏移量(也就是直接a[index]的方式)来访问每一个元素对象,但它也有它的缺点,轻易造成内存碎片,进而内存溢出:

每次构造都必要一大片一连内存空间才能构造出来,所以即使中心有些不是一连空出来的空间也只能浪费掉。
而单链表如果要访问第三个对象(比云云时有三个对象),则必须先要知道第二个对象的地址,而第二个对象又必须要靠第一个对象来获取,因此这就必要从头开始遍历才能终极访问到第三个对象。但单链表的利益就是,如果要在某个位置上插入或者删除某个节点对象,直接操作就可以(把它的指向下一个对象的引用的指向举行更改就可以)。

可以看到,创建链表不必要一大块一连内存空间,通过next引用的指向就能达到一个连一个,像一条链一样。了解单链表之后,回到enqueueMessage()方法来继承分析:
boolean enqueueMessage(Message msg, long when) {

msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
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 {

}

这段代码其实很好明白,第一条消息进来时,P对象为空,mMessages对象也是为空,然后此时p==null成立,因此走if里面的代码块,然后让当前这条要发送的消息的下一个消息对象next引用指向p(也就是null),然后让mMessages即是当前消息对象。

那么当第二条消息进来时,又重新new了一个p对象,让它即是mMessage(也就是第一条消息对象),这次进来就必要判断第二条消息的时间是不是小于第一条消息的时间,也就是when < p.when是否成立,如果是小于的环境,那么就让当前消息对象msg(也就是第二条消息)的下一个指向next引用指向p(也就是第一条消息对象),而此时mMessages对象即是第二条消息对象,那现在这种环境也就是说如果我发送的第二条消息对象的时间是比第一条消息对象的时间还要小的话,那么就会让第二条消息排在第一条消息对象的前面,也就是先让第二条消息先发送:

第三条消息的时间也是比第二条消息要小,所以依然第三条消息的next引用指向第二条消息对象,那么当第四条消息对象的时间是比第三条消息对象的时间要大的话,则就走else块的代码,来看看会发生什么:
boolean enqueueMessage(Message msg, long when) {

msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
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 (;

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

三尺非寒

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表