Handler 中有四个关键类
- Message
- Handler
- MessageQueue
- Looper
介绍一下这四个类的作用
Message
Meaage实现了Parcelable接口,从这里就可以看出,它是一个可序列化的类
在发送消息前,需要把消息事件包装为Message,这里有几个注意事项:
1、这里推荐使用Message.obtain() 来创建Message对象,
2、在每次发送消息前创建Message对象,避免Message对象存在的时间太长,而且在发送Message消息前要使用handler.hasMessages()进行判断,是否已经有此消息,如果有,根据需要进行移除获取return操作。这里的操作都是为了避免出现RuntimeException:This Message is aleady in use的异常。
Handler
用于接收消息,最终处理消息
Handler在构造过程中会确立以下几件事:
- 获取当前Handler实例所在线程的Looper对象,mLooper = Looper.myLoopper();
- 如果Looper不为空,则获取Looper的消息队列,赋值给Handler的成员变量mQueue:mQueue = mLooper.mQueue
- 可以设置CallBack来处理消息回调:mCallback = callback
Handler创建过程可以看出其两个特性:
- Handler只能绑定一个线程的Looper;
- Handler的消息是发送给Looper的MessageQueue, 需要等待处理;
所以,如果在子线程中声明了一个Handler,是不能直接更新UI的,需要在Handler的构造方法中传入主线程的Looper。
并且要注意,子线程没有默认的Looper,在子线程创建Handler之前,必须先开启子线程的Looper,否则会爆出异常。
- 发送消息关键方法:
Handler sendMessage(),最终调用到sendMessageAtTime,调用enqueueMessage,将消息传入MessageQueue, - 接收消息关键方法
Handler dispatchMessage(),如果Message的Callback不为空,则回调到Message的Callback中,如果Message中的Callback为空,则判断Handler中的Callback是否为空,如果不为空,则回调到Handler中的Callback来处理,如果都没有传入Callback,则由handleMessage 处理
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
MessageQueue
主要功能有两个,一个插入消息,关键方法enqueueMessage,一个取出消息next,通过单向链表的数据结构来存储消息。下面结合源码进行理解。
boolean enqueueMessage(Message msg, long when) {
// 如果msg没有target则抛出异常,target就是Handler
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
...
//插入消息时,因为是队列,有先后之分,需要同步
synchronized (this) {
...
msg.markInUse();
msg.when = when; // when是系统开机时间+延迟时间,得出的消息执行时间
Message p = mMessages; // 头部消息
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// p == null 代表当前消息队列中没有消息
// when == 0 代表系统刚开机,基本不可能出现
// when < p.when 代表此消息的执行时间早于此队列中所有的消息
// 将此消息放置在消息队列的头部
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// 插入队列中间。通常我们不必唤醒事件队列,
// 除非队列的头部有障碍物,
// 并且消息是队列中最早的异步消息。
// (p.target == null 则代表他是一个同步屏障,且当前消息为异步消息,异步消息优先)
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
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.
if (needWake) {
// 这个方法可以让nativePollOnce立即返回
nativeWake(mPtr);
}
}
return true;
}
Message next() {
// 如果消息循环已退出并已被释放,请返回此处。如果应用程序在退出后尝试重新启动循环器,则可能会发生这种情况,这是不受支持的。
// native中MessageQueue的地址值
final long ptr = mPtr;
if (ptr == 0) {
// 如果为0 则说明应用已退出
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
// 本方法就是执行native消息层
// nextPollTimeoutMillis是超时等待时间,如果为-1 则表示无限等待,这个方法会阻塞循环
// 如果值为0 ,则无需等待立即返回
// 通过Linux的epoll机制进行阻塞
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 && msg.target == 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;
}
// 下面是进行一些idleHandler的处理
// 此处暂时不展开了
...
}
...
}
}
Looper
Looper是自从启动后就开始无限循环,不断的从消息队列中获取消息,然后分发处理事件,APP启动时,在ActivityThread的main()方法中已经启动了Looper循环,关键方法 loop();一下是源码中的loop方法:
/**
119 * Run the message queue in this thread. Be sure to call
120 * {@link #quit()} to end the loop.
121 */
122 public static void loop() {
123 final Looper me = myLooper();
124 if (me == null) {
125 throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
126 }
127 final MessageQueue queue = me.mQueue;
128
129 // Make sure the identity of this thread is that of the local process,
130 // and keep track of what that identity token actually is.
131 Binder.clearCallingIdentity();
132 final long ident = Binder.clearCallingIdentity();
133
134 for (;;) {
135 Message msg = queue.next(); // might block
136 if (msg == null) {
137 // No message indicates that the message queue is quitting.
138 return;
139 }
140
141 // This must be in a local variable, in case a UI event sets the logger
142 Printer logging = me.mLogging;
143 if (logging != null) {
144 logging.println(">>>>> Dispatching to " + msg.target + " " +
145 msg.callback + ": " + msg.what);
146 }
147
148 msg.target.dispatchMessage(msg);
149
150 if (logging != null) {
151 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
152 }
153
154 // Make sure that during the course of dispatching the
155 // identity of the thread wasn't corrupted.
156 final long newIdent = Binder.clearCallingIdentity();
157 if (ident != newIdent) {
158 Log.wtf(TAG, "Thread identity changed from 0x"
159 + Long.toHexString(ident) + " to 0x"
160 + Long.toHexString(newIdent) + " while dispatching to "
161 + msg.target.getClass().getName() + " "
162 + msg.callback + " what=" + msg.what);
163 }
164
165 msg.recycleUnchecked();
166 }
167 }
重点流程
1、获取Looper对象
2、获取MessageQueue对象
3、死循环遍历
4、通过queue.next获取一条Message
5、通过msg.target.dispatchMessage(msg) 分发Message
6、通过msg.recycleUnchecked() 回收Message到消息池中