Handler是Android系统提供的一种异步回调机制,也可以理解成线程的消息机制。为了避免ANR,我们通常会把一些耗时的操作(I/O,网络请求,复杂计算等)放到子线程去执行,执行完毕之后需要通知主线程更新UI操作,这个时候就需要Handler机制来处理
在主线程中创建Handler实例,并实现handleMessage方法
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
//执行相关修改UI的操作
}
}
};
在子线程中获取Handler对象,并在需要更新ui的地方用获取的handler对象发送消息;
Message msg = Message.obtain();
msg.obj = "content";
msg.what = 1;
//发送消息给Handler
handler.sendMessage(msg);
每个Handler都会关联一个消息队列,消息队列又是封装在Looper当中的,每个Looper又会关联一个线程。这样三者就关联上了。
Handler是一个消息处理器,将消息发送给消息队列,然后再由相应的线程从消息队列中逐个取出,并执行。
主线程的消息队列是在Looper.prepareMainLooper()方法创建的,最后执行Looper.loop() 方法来循环取消息
下边我们结合代码一起来一下:
首先来看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;
}
从Handler的初始化,我们可以看到,初始化的同时会通过Looper.myLooper()获取了一个Looper对象,并与Looper进行了关联,然后通过Looper对象获取了消息队列。我们继续深入到Looper的源码中Looper.myLooper()是怎么实现的。
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
从上面的程序可以看出,通过prepareMainLooper(),内部调用prepare(boolean quitAllowed)方法创建了一个Looper对象,并通过sThreadLocal.set(new Looper(quitAllowed))方法,设置给了sThreadLocal;
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
通过Looper的预备工作,sThreadLocal中存储了一个Looper对象,然后myLooper()方法通过sTreadLocal获取到了Looper对象,那么消息队列就跟线程关联上了,所以各个线程只能访问自己的looper。
综上所述,我们可以发现,消息队列通过Looper与线程关联,而Looper又是跟Handler关联的,所以这三者就有了联系。
在创建Looper对象后,通过Handler发来的消息放在消息队列中后是如何被处理的呢?这就涉及到了消息循环,消息循环是通过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.");
}
if (me.mInLoop) {
Slog.w(TAG, "Loop again would have the queued messages be executed"
+ " before this one completed.");
}
me.mInLoop = true;
final MessageQueue queue = me.mQueue;
//省略
// 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();
}
}
只看主干线路,loop()方法实质上就是通过一个死循环不断的从消息队列中获取消息,然后又不断的处理消息的过程。
我们从loop中的 dispatchMessage()方法入手,看看谁是该方法的调用者,深入Message源码中看看target的具体类型:
public final class Message implements Parcelable {
public long when;
/*package*/ Bundle data;
@UnsupportedAppUsage
/*package*/ Handler target;
@UnsupportedAppUsage
/*package*/ Runnable callback;
// sometimes we store linked lists of these things
@UnsupportedAppUsage
/*package*/ Message next;
}
源码中我们可以看到其实target就是Handler类型。所以Handler是将消息发送到消息队列暂时存储下,然后又将消息发送给Handler自身去处理。那我们继续到Handler源码中去看看Handler是如何处理消息的:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
/**
* Subclasses must implement this to receive messages.
* 消息处理方法为一个空方法,由子类去实现
*/
public void handleMessage(Message msg) {
}
从上面的源码中可以看出,dispatchMessage(Message msg)只负责分发Message。从Message源码中我么可以知道callback为Runnable类型,如果callback不为空,则执行 handleCallback方法来处理,而该方法又会调用callback.run();如果如果callback为空,则调用handleMessage来处理消息,而该方法又为空,所以我们会在子类中重写该方法,并将修改UI的代码写在里面。之所以会出现这两种情况,是因为Handler发送消息有两种形式:
在本文的一般使用步骤中,我使用的是sendMessage(msg)发送消息,此时callback就为空。
当使用post发送消息时,callback就不为空。
以上就是Handler机制的原理,大致可以总结为:在子线程中Handler将消息发送到MessageQueue中,然后Looper不断的从MessageQueue中读取消息,并调用Handler的dispatchMessage发送消息,最后再Handler来处理消息。