Android的Handler消息机制 解析
2019-04-01 本文已影响15人
YuanchaoLi
Android的Handler消息机制
实现原理
- 主线程会自动调用Looper.prepareMainLooper和Looper.loop,具体是在ActivityThread中main方法中调用的。
public static void main(String[] args) {
......省略无关代码
// 主线程的Looper相关准备工作
Looper.prepareMainLooper();
// Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
// It will be in the format "seq=114"
long startSeq = 0;
if (args != null) {
for (int i = args.length - 1; i >= 0; --i) {
if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
startSeq = Long.parseLong(
args[i].substring(PROC_START_SEQ_IDENT.length()));
}
}
}
// 生成主线程
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
// 拿到主线程的Handler,并将主线程的Looper绑定到Handler中
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// 开启消息循环
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
- 子线程使用Handler时,首先需要调用Looper.prepare,prepare方法中,new一个Looper对象,存入ThreadLocal;在Looper的构造中,会new一个MessageQueue,绑定到当前Looper中。
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// new一个Looper对象
sThreadLocal.set(new Looper(quitAllowed));
}
private Looper(boolean quitAllowed) {
// new一个MessageQueue,绑定到Looper中
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
- 创建Handler实例,在Handler构造中,若传入Looper,则将传入的Looper绑定给Handler的Looper,并将传入Looper的MessageQueue也绑定给Handler的MessageQueue。若不传入Looper,则构造中,直接取当前线程的Looper以及该Looper的MessageQueue和handler绑定。
// 创建Handler选择无参构造,会走到这里
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
// 拿到当前线程的Looper,绑定到Handler中
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
// 拿到当前线程Looper的MessageQueue,绑定到Handler中
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
// 创建Handler选择有参构造,会走到这里
public Handler(Looper looper, Callback callback, boolean async) {
// 将传入的Looper以及该Looper的MessageQueue绑定到Handler中,让Handler在Looper所在的线程环境中
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
- 接着调用Looper.loop,拿到myLooper,也就是从ThreadLocal中取,在拿到myLooper的MessageQueue,对MessageQueue死循环,MessageQueue.next()获取消息,没有消息则挂载。有消息时,会调用message的target的dispatchMessage方法分发消息。dispatchMessage方法中,首先判断message是否有回调,有则直接将新消息传递给回调接口的run方法中。若message没有回调,则再判断handler是否有回调,有回调,则将新消息传递给回调接口的handleMessage方法中。若handler也没有回调,则将消息传递给handler的handleMessage公开方法中。外部重写该方法即可接收处理新消息。
public static void loop() {
// 拿到Looper
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
// 拿到Looper的MessageQueue
final MessageQueue queue = me.mQueue;
......省略无关代码
// 对MessageQueue死循环
for (;;) {
// MessageQueue.next()获取消息
Message msg = queue.next(); // might block
// 没有消息则挂载
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
......省略无关代码
try {
// 有消息时,调用message的target的dispatchMessage方法分发消息
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
......省略无关代码
msg.recycleUnchecked();
}
}
// Handler分发消息
public void dispatchMessage(Message msg) {
// Message有回调,则直接将新消息传递给回调接口的run方法中
if (msg.callback != null) {
handleCallback(msg);
} else {
// Handler有回调,则将新消息传递给回调接口的handleMessage方法中
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
// 将消息传递给handler的handleMessage公开方法中
handleMessage(msg);
}
}
- hander.sendMessage,会调用enqueueMessage方法,将当前handler赋值给Message的target,然后调用handler的MessageQueue的enqueueMessage方法,内部会将新的message添加进MessageQueue中。此时,Looper中MessageQueue会被唤醒,循环获取到新消息做下一步处理。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
// 将当前handler赋值给Message的target
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
// 调用MessageQueue的enqueueMessage方法,内部会将新的message添加进MessageQueue链表中
return queue.enqueueMessage(msg, uptimeMillis);
}
相关概念
- 一个线程对应一个Looper,一个Looper对应一个MessageQueue,一个Looper可对应多个Handler,一个Handler对应一个Looper。
- 主线程中,MessageQueue死循环,并不会卡死UI。在ActivityThread的main方法中,首先调用Looper.prepareMainLooper,紧接着就会new一个ActivityThread,并且拿到该主线程的mainThreadHandler,再调用Looper的loop开启消息循环。以后UI线程的UI刷新等操作也是在mainThreadHandler发消息执行的。