Handler工作原理解析
Android的消息机制主要是指handler的运行机制,我们都知道handler工作体系,不只是自身,还包括looper和messagequeue,这三者是一个整体,缺一不可,只不过我们在开发过程中较多的接触handler罢了。
为什么要用handler
Android有一条规则,那就是子线程不能更新UI,可能有人会问什么。很简单,各个view在高并发的环境下有可能会崩溃,它们内部实现都没有用线程的锁机制。可能又有人问为什么不用锁机制呢,也很容易想到,UI渲染是个耗时的动作,加锁无疑会更耗时,用户体验不好,就不能这样搞,我想这东西加锁的话实现起来也麻烦吧。所以就引出了Handler这个东西,我们只需要通过handler切换一下UI访问的线程,这些就迎刃而解了。
Handler原理详述
先简述一下原理,下面会细说,这样有助于读源码。handler通过send或者post方法向消息队列插入一条消息,looper内部有个死循环一直调用messagequeue的next方查看是否有新消息,messagequeue的next方法会把这条消息返回给looper,同时还会把消息移除链表,如果消息不会空,就会交给handler的dispatchMessage方法来处理了,looper是运行在创建handler的那条线程中,我们一般都是在主线程直接new的,这样一来就实现了UI线程的切换。
前面提到handler体系的三个元素:handler、looper、messagequeue,下面我来说一下这三者主要是干嘛用的。
handler:主要用来消息的发送和接收
messagequeue:消息的插入删除
looper:循环检验是否有新消息到来
handler的发送过程主要是调用send和post方法,而post最终还是会调用send方法,我们来看一下post的源码,下面是post方法的最终实现:
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
不难看出,这里其实主要还是调用了消息队列的方法,执行插入操作,接着looper的loop方法在死循环检验next方法是否为null,这里需要注意next方法返回这条消息后会将他从消息队列中移除,如果消息不为null,就执行handler的dispatchmessage方法,下面看一下looper的实现:
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
// Allow overriding a threshold with a system prop. e.g.
// adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
final int thresholdOverride =
SystemProperties.getInt("log.looper."
+ Process.myUid() + "."
+ Thread.currentThread().getName()
+ ".slow", 0);
boolean slowDeliveryDetected = false;
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
// Make sure the observer won't change while processing a transaction.
final Observer observer = sObserver;
final long traceTag = me.mTraceTag;
long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
if (thresholdOverride > 0) {
slowDispatchThresholdMs = thresholdOverride;
slowDeliveryThresholdMs = thresholdOverride;
}
final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
final boolean needStartTime = logSlowDelivery || logSlowDispatch;
final boolean needEndTime = logSlowDispatch;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
Object token = null;
if (observer != null) {
token = observer.messageDispatchStarting();
}
long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
try {
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);
}
}
if (logSlowDelivery) {
if (slowDeliveryDetected) {
if ((dispatchStart - msg.when) <= 10) {
Slog.w(TAG, "Drained");
slowDeliveryDetected = false;
}
} else {
if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
msg)) {
// Once we write a slow delivery log, suppress until the queue drains.
slowDeliveryDetected = true;
}
}
}
if (logSlowDispatch) {
showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
looper调用handler的dispamessage方法之后,消息就传给handler来处理了,先看一下源码:
/**
* Callback interface you can use when instantiating a Handler to avoid
* having to implement your own subclass of Handler.
*/
public interface Callback {
/**
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
boolean handleMessage(@NonNull Message msg);
}
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(@NonNull Message msg) {
}
/**
* Handle system messages here.
*/
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
在这个方法里,会先判断msg.callback和mCallback是否为空,第一种情况如果都为空的话,最终就会调用handleMessage方法,这个就很熟悉了吧,就是我们在创建Handler对象的时候重写的那个方法,另外的一种情况就是把这个消息重新加入消息队列,后面就又走一遍流程了,到这里handler的基本原理就说完了,有一些细节其实没说到,去看一下源码应该会有所体会的。 到这,Handler发送消息,到handleMessage处理消息就完成了一次线程间通信。