带你一步一步深入Handler源码,拿下面试官不在话下!(1)

}).start();
}

在对某件实物进一步了解之前,我们要先对该事物的价值意义有一个理解,即他是做什么的,再明白事物产生或发生时做了什么,结束时又会有什么样的结果。我们要讨论研究的是这个过程到底经历了什么,是发生什么因,再经历什么产生这个果。

当调用Handler发送消息相关方法时,会把这个消息发送到哪儿去?从上面的示例代码中可以看到消息最终还是会回到Handler手上,由他自己处理。我们要搞清楚的就是这个消息由发到收的过程。

####消息会发送到哪儿去?

mTestHandler.sendEmptyMessage(1);

我们追随sendEmptyMessage()方法下去:

Handler无论以何种方式发送何种消息,都会经过到sendMessageAtTime()方法:

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

而此方法会先判断当前Handler的mQueue对象是否为空,再调用enqueueMessage()方法,从字面意思不难理解是将该消息入队保存起来。再看enqueueMessage()方法:

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}

public final class Message implements Parcelable {
//…
Handler target;
}

该方法会先将Message和当前Handler绑定起来,不难理解当需要处理Message时直接甩给绑定他的Handler就是了。再调用queue.enqueueMessage()方法正式入队,而queue对象到底是一个什么样的对象?由单向链表实现的消息队列。queue.enqueueMessage()方法就是遍历链表将消息插入表尾保存起来,而从queue取消息就是把表头的Message拿出来。

接着来搞清楚queue他是何时怎样创建的?来看Handler的构造函数。

public Handler(Callback callback, boolean async) {
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
“Can’t create handler inside thread that has not called Looper.prepare()”);
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}

Handler的构造方法会先调用Looper.myLooper()方法看能不能获取一个Looper对象,如果获取不到程序就直接蹦了。再从该Looper对象中获取我们需要的消息队列。

Looper到底是一个怎样的对象,有这怎样的身份,在Handler机制中扮演这怎样的角色?来看myLooper()方法:

public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}

myLooper()方法会直接就从sThreadLocal对象中获取Looper,而sThreadLocal是一个ThreadLocal类对象,而ThreadLocal类说白了就是通过他存储的对象是线程私有的。

static final ThreadLocal sThreadLocal = new ThreadLocal();

调用get()方法直接从ThreadLocal中获取Looper,接下来就得看是何时set()将Loooper对象保存到ThreadLocal中去的。Looper.prepare()方法:

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

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

从这段源码可以看出,Looper不仅是线程私有的还是唯一不可替换。Looper对象创建时会初始化MessageQueue()对象,正是我们需要的队列。
之所以最上面的示例代码中我们并没有调用prepare()方法初始化Looper,程序也没有崩溃,那是因为在ActivityThread的Main方法中就已经初始化了Looper对象。

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

到此我们算是明白消息会发送到哪儿去了,现在就要知道的是怎么取出消息交给Handler处理的。

首先MessageQueue封装有完整的添加(入队)和获取/删除(出队)方法,MessageQueeue.next()方法将链表当中表头第一个消息取出。

Message next() {
//…
for (;😉 {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}

nativePollOnce(ptr, nextPollTimeoutMillis);

synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
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;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
nextPollTimeoutMillis = -1;
}

if (mQuitting) {
dispose();
return null;
}
//…
}
//…
}
}

代码虽然比较多,我们从第三行和第39行开始说起。next()方法实际是一个死循环,会一直从当前队列中去取Message,即使当前队列没有消息可取,也不会跳出循环,会一直执行,直到能够从队列中取到消息next()方法才会执行结束。其次当Looper调用quit()方法,mQuitting变量为ture时会跳出死循环,next()方法返回null方法也会执行结束。上面提到在ActivityThread中的main()方法中会初始化Looper,其实在不久之后便会开始从队列中取消息。

public static void main(String[] args) {

//…
Looper.prepareMainLooper();

ActivityThread thread = new ActivityThread();
thread.attach(false);

if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}

if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, “ActivityThread”));
}

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();

throw new RuntimeException(“Main thread loop unexpectedly exited”);
}

调用Looper.loop()方法就会开始遍历取消息。

public static void loop() {
for (;😉 {
Message msg = queue.next(); // might block
if (msg == null) {
return;
}

final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}

final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;

final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
final long end;
try {
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
}

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
roid开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门**

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值