前言
在Android的日常使用中,Handler的使用大家应该都不陌生,今天这篇文章会从Android SDK源码的角度分析Handler的实现原理。
Handler的使用
public static Handler mHander = new Handler(){
@Override
public void handleMessage(Message message){
switch (message.what){
case 0:
break;
case 1:
break;
default:
break;
}
}
};
在主线程使用时,我们只需要在Activity或Handler中像上面一样创建一个新的Handler实例类,在需要发送消息的地方调用sendMessage()方法就可以进行Handler的使用了,这里发送消息的方法不唯一,还有其他的发送方法。
Handler的基本原理说明
学习过Handler的原理的同学都知道,Handler包括四个部分,Handler,Looper,MessageQueue,Message组成,当Messge到达以后会添加进MessageQueue消息队列,Looper负责循环遍历消息队列,当有消息时从队列中取出并用Handler进行回调。
Handler源码解析
首先我们打开Handler的源码.
(如果你的应用的开发SDK版本和你的Android Studio所下载的SDK版本不匹配的话是无法看到详细的代码的,只能看到.class文件,解决这个问题只需要在SDK Manager中下载对应的SDK,重启一下Android Studio即可,ps:必须重启AS)
处理消息的核心原理
我们知道处理消息都是复写handleMessage方法,所以我们先去源码里查看这个方法
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(@NonNull Message msg) {
}
注释也写的很清楚,那就子类必须实现这个方法来接收消息。
那么我们继续看源码,看接收到消息时是如何执行到这个方法的,因此我们通过搜索查到了dispatchMessage()这个方法,所以我们继续看
/**
* 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是否为null,那么先看判断的具体内容是什么。我们打开Message的源码,发现了有这样的一个变量
@UnsupportedAppUsage
/*package*/ Runnable callback;
所以callback的本质是一个Runnable接口。那么它什么时候才不为空呢,我们查看Message的源码,经过关键字搜索可以看到如下几个地方可以赋值。
1.静态的Message构造方法
public static Message obtain(Message orig) {
Message m = obtain();
m.what = orig.what;
m.arg1 = orig.arg1;
m.arg2 = orig.arg2;
m.obj = orig.obj;
m.replyTo = orig.replyTo;
m.sendingUid = orig.sendingUid;
m.workSourceUid = orig.workSourceUid;
if (orig.data != null) {
m.data = new Bundle(orig.data);
}
m.target = orig.target;
m.callback = orig.callback;
return m;
}
2.Obtain()方法
public static Message obtain(Handler h, Runnable callback) {
Message m = obtain();
m.target = h;
m.callback = callback;
return m;
}
3.setCallback()方法
@UnsupportedAppUsage
public Message setCallback(Runnable r) {
callback = r;
return this;
}
所以可以通过调用Message中的这几个方法来手动设置callback。
继续看代码,当msg.callback不为空时调用handleCallback()方法,那么我们看一下handleCallback()方法。
private static void handleCallback(Message message) {
message.callback.run();
}
代码很简单,就是运行了Runnable接口的run()方法。
那么当msg.callback为空时,开始判断mCallback是否为空。我们开始查看mCallback的来源。
@UnsupportedAppUsage
final Callback mCallback;
通过查看handler类,赋值的方式有下面几个地方
1.Handler构造方法
public Handler(@Nullable 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());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
2.Handler的构造方法
@UnsupportedAppUsage
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
因此在创建Handler实例时我们可以设置mCallback,那么我们接着看,当它不为空时,执行mCallback.handleMessage(msg),那我们回头看一下这个Callback接口的定义。
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);
}
当我们总结的msg.callback和mCallback都为空时,执行handleMessage(msg)方法。所以我们大致梳理一下,执行消息的核心判断条件就是Message中的callback或Handler中的mCallback是否为null。我们接下来看消息如何被检测到并开始处理的。所以我们通过dispatchMessage()方法查找消息如何被分配的.
这里比较难找,我在看的过程中通过仔细对比才发现真正调用消息分发的地方在Looper.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();
}
}
这里的代码较多,涉及到了未向开发者开放的一些接口,所以我们只关注如何调用分发消息,这个方法里有一个死循环,即for(; ; ),这种写法比while(true)更好,其理由涉及到了一些底层的知识,有兴趣的可以自行去查阅,这个方法里,通过将Looper对象里所定义的MessageQueue对象循环遍历,取出消息,再通过每个Message种所定义的Handler实例对象target,来调用dispatchMessage(),从而实现消息的获取。
我们再分析消息的发送,我们常用的发送消息的方法是sendMessage(Message),那么我们就从这个消息开始看,通过sendMessage(Message)的不断查找,我们最终在MessageQueue对象里发现了如何发送消息
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
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) {
nativeWake(mPtr);
}
}
return true;
}
这个方法核心思路就是通过判断传来的Message对象中,根据Handler是否存在和所处的子线程是否在运行来判断是否将该Message对象放进消息队列中,至此我们差不多就了解了整个消息发送和处理消息的原理了,我们简单总结一下:
- 在创建Handler时,我们复写了handleMessage(),用来做消息处理的具体实现。
- 当在子线程创建Handler时,我们需要手动调用Looper.prepare(),和Looper.loop(),loop()中包含一个死循环,遍历消息MessageQueue,主线程时不需要,因为ActivityThread中已经帮我们做了这步操作。
- 当我们调用到sendMessage时,Message会根据Handler是否创建和线程是否保活来确定是否将该Message加入消息队列中。
- 当消息进入队列以后,符合条件的会执行Handler中的dispatchMessage方法,判断Message是否设置了callback,如果设置了则调用callback.run(),或Handler是否设置了callback,如果设置了则调用handleMessage()方法。至此我们的消息就成功的被处理了.
所以我们思考一下,能否让多个Handler同时处理一条消息?
答:当然可以,因为Looper遍历了属于自己的MessageQueue,那么我们只要在创建handler时,将多个Handler的Looper设置成一致就可以了~因此我们也就延申出了线程通信的方式,通过Looper的设置来实现线程间的通信。
网友评论