这篇文章介绍一下Handler的原理,仅用于个人适当回顾学习。
一.功能介绍
1.用于线程间的通讯,可以通过handler进行切换UI线程进行绘制UI。
2.用户控制延时的消息传递。
二.重要的类介绍
1.Message:
数据载体,通过handler进行数据传递的对象就是message。可以存入多个参数。
2.MessageQueue:
其实从名字就可以看出,这是一个队列,平时我们使用handler进行消息传递的时候,事实上是将message对象放入当前队列中。
3.Looper
既然有队列,那么肯定有对队列进行操作的管家。而looper就是这个管家。一个handler对应一个looper,一个looper内部也持有一个MessageQueue对象。
4.ThreadLocal
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());
}
}
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。然后再通过looper获取对应的MessageQueue。
我们先分析一下Looper.myLooper()对应的代码
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
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));
}
这里我放了两段代码,分别是获取looper。可以看到其实looper是从,ThreadLocal中获取的,而ThreadLocal刚好又可以对线程间的数据进行存储。说白了就是获取当前线程的对象。
同时看到prepare方法,其实所有的handler都是首先要创建对应的Looper对象。就是通过prepare方法。而在主线程不需要,是因为主线程已经默认帮我们创建好了这个对象。
前面我讲过looper其实是一个管家,用于处理queue中的消息,那么这个管家是如何工作的呢,我们就看下面一个来自Looper的方法
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;
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
try {
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
}
以上是我截取的部分代码,从上面可以看出,其实looper在调用loop方法后开始工作,而loop的工作方式,其实就是不断循环,如果发现queue之中有消息的话,就对消息进行处理,如果没有的话继续循环。
看明白了消息的传递,那么对于handler的消息使用就很明白了,我们看下面handler的一个sendMessage的方法。
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
相信你已经明白了吧,就是把消息存入队列queue之中,存入之后,循环中的looper对象发现queue之中多了一个消息,就对他进行处理。
刚去晚上到了一张图来,希望你能看明白