Handler系列—Message对象的获取机制
Posted datian1234
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Handler系列—Message对象的获取机制相关的知识,希望对你有一定的参考价值。
为什么android建议Message.obtain(),而不是直接用new关键字
前言
一般情况下,用Handler发送一个消息,即Message对象,可以通过new关键字创建,也可以通过Message.obtain()创建,在Android源码中,Message的构造方法上边可以看到如下注释:
/** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}).
*/
public Message() {
}
注释意思是:首选Message.obtain()来获取Message对象
为什么Android要推荐使用Message.obtain()方法来获取呢???让我们来看看源码里的奥妙,一起来fucking the source code
源码分析Message.obtain()方法
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*
* 从一个pool里获取Message实例,允许我们在多种情况下,避免分配新的对象
*/
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
可以看到,如何sPool对象为null,则new一个Message对象;如果不为空,就把sPool的第一个节点对象返回,然后把sPool指向下一个节点。那么sPool到底是什么呢???其实他就是一个Message链表,每个Message里都有一个next字段,类型也是Message对象。
到这里也看到了Message对象的获取方式分为两种情况
总结:
如果sPool为null,则直接通过new来获取
如果sPool不为null,则将sPool的第一个节点返回,然后把sPool指向其下一个节点
那么这里又有一个问题,sPool是什么时候生成和赋值的,什么时候向sPool池中添加Message对象的呢?接下来我们通过源码定位到了recycleUnchecked()这个方法,这个方法又是在recycle()方法中调用的
源码解析recycle()和recycleUnchecked()方法
public void recycle() {
//判断当前message是否可以被回收(是否正在被使用)
if (isInUse()) {
if (gCheckRecycle) {
throw new IllegalStateException("This message cannot be recycled because it "
+ "is still in use.");
}
return;
}
//当前message对象可以被回收
recycleUnchecked();
}
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
//这些就是清除当前message对象的成员变量信息(相当于一个新的message)
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = UID_NONE;
workSourceUid = UID_NONE;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
//当前池中的size小于最大size,就为池中添加当前message
//MAX_POOL_SIZE 大小默认为50
if (sPoolSize < MAX_POOL_SIZE) {
//当前message作为sPool的第一个节点
next = sPool;
//再将当前message赋值给sPool
sPool = this;
sPoolSize++;
}
}
}
这两个方法的源码还是比较容易看懂的,基本总结就是当message对象被回收的时候,先清除其成员变量信息,然后将该对象作为sPool池的第一个节点添加到池中。
那么问题又来了,message对象什么时候被回收呢???咱们可以猜想一下,当message对象不用了之后被回收;那么在Android的消息机制中,是通过Looper.loop()方法从消息队列中取出消息进行处理,那么咱们就去这个方法里去寻找我们想要的答案
解析Looper.loop()
public static void loop() {
final Looper me = myLooper();
//首先判断Looper对象为空,则直接抛异常
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
//省略部分代码
......
......
//通过looper拿到消息队列
final MessageQueue queue = me.mQueue;
//省略部分代码
...
...
//开启循环来从消息队列中取消息
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//省略部分代码
......
......
try {
//将message对象交给hadler的dispatchMessage方法进行处理消息
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
if (observer != null) {
observer.dispatchingThrewException(token, msg, exception);
}
throw exception;
} finally {
ThreadLocalWorkSource.restore(origWorkSource);
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
//省略部分代码
......
......
//终于。。。看到了我们熟悉的方法了
msg.recycleUnchecked();
}
}
通过源码,可以清楚的看到,当处理完消息后,会调用Message的回收方法,即在sPool里添加一个消息
总结
源码里可以看到,Message对象里维护了一个sPool对象,其实就是一个Message链表,默认长度为50。在消息机制中,每次obtain()获取Message对象的时候,如果sPool为空,则直接new一个出来,如果不为空,则取第一个节点的message对象;然后在Looper.loop()里进行轮询处理消息的时候,每次处理完一个消息,就把该消息插入到sPool的第一个节点中去。这样设计的目的就是维护一个消息池,如果池中有复用的Message,则拿出来复用,避免频繁创建和销毁Message带来的内存和性能消耗。
Android系统中,每个应用程序是由Android的Activity,service,Broadcast,contentProvider这四剑客的中一个或多个组合而成,这四剑客所涉及的多进程间的通信底层都是依赖于Binder lPC机制。例如当进程A中的Activity要向进程B中的Service通信,这便需要依赖于Binder IPC。不仅于此,整个Android系统架构中,大量采用了Binder机制作为IPC(进程间通信)方案,当然也存在部分其他的IPC方式,比如Zygote通信便是采用socket。
Binder作为Android系统提供的一种IPC机制,无论从事系统开发还是应用开发,都应该有所了解,这是Android系统中最重要的组成,也是最难理解的一块知识点,错综复杂。要深入了解Binder机制,最好的方法便是阅读源码,借用Linux鼻祖Linus Torvalds曾说过的一句话: Read The Fucking source code 。
以上完整学习笔记pdf全部免费分享,需要的朋友只需要点赞支持一下后,【点击这里直达免费获取方式】。
以上是关于Handler系列—Message对象的获取机制的主要内容,如果未能解决你的问题,请参考以下文章
Android Handler消息机制03-Message源码学习