关于Handler和Looper的知识相信网上有很多介绍,既然有这么多介绍,为啥还要写这篇文章呢?当然是我写的好理解了啊 哈哈哈~~ 结合源码分析他们是这么工作的,为啥子线程的东西通过Handler发送消息就能跑到主线程里运行了,相信很多文章都没有说的很详细。为啥这么肯定别人说的不详细?那是因为我也搜过啊,看了半天还不如自己结合源码分析一下。。。好了废话不多说,开撸:
我们分析的过程按照开发时的使用过程来进行分析,容易理解:
首先我们实例化Handler:
Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
// 自己的处理逻辑
};
};
我们看看Handler的构造函数都干了什么:
#代码块1
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
// 这里忽略FIND_POTENTIAL_LEAKS就是个静态常亮false
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并保存下来
mLooper = Looper.myLooper();
// 这个异常就是当前线程中如果没有调用过Looper.prepare()那么Looper.myLooper()得到的就是null,我们在主线程中实例化Handler的时候不用关心,主线程启动的时候会实例化好了Looper,具体的代码实在ActivityThread类中的main方法中,下面会给大家分析到。
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
// 把当前线程的looper对象的消息队列保存下来
mQueue = mLooper.mQueue;
// 这个Callback是Handler里定义的一个回调,这里是null
mCallback = callback;
// 这个我们忽略就好了,不影响我们分析,喜欢深入挖掘的自行分析
mAsynchronous = async;
}
构造把当前线程的looper对象保存了下来,把looper中的消息队列保存了下来。
想想我们发送消息是怎么操作的,调用了sendMessage方法,下面就看看sendMessage方法干了些什么:
#代码块2
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
// 参考代码块1中的分析,这里的queue就是消息队列
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) {
// 消息的target,也就是谁发送的它
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
// 调用了MessageQueue的enqueueMessage方法,就是把消息添加到了消息队列中
return queue.enqueueMessage(msg, uptimeMillis);
}
一路追踪发现sendMessage其实就是把消息加入到了消息队列中为Message的target附了值,就是发送它的那个handler。
队列中的message是怎么被处理的呢?我们接着看:
在ActivityThread的main方法中:
#代码块3
public static void main(String[] args) {
// ...
Looper.prepareMainLooper(); // 实例化looper
// ...
Looper.loop(); // 开启消息循环
}
调用了Looper的prepareMainLooper()方法,然后调用了Looper.loop();启动了消息循环。
回想一下我们在子线程中怎么使用Looper的:
#代码块4
Looper.prepare(); // 实例化looper
// ...
Looper.loop(); // 开启消息循环
是不是和#代码块3的有些像,只是一个调用的是prepareMainLooper,一个调用的是prepare。
下面我们就分析Looper都干了些什么,先从prepareMainLooper和prepare分析:
#代码块5
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
public static void prepare() {
prepare(true);
}
// true表示当前消息队列可以退出,false表示不可以。
private static void prepare(boolean quitAllowed) {
// 每个线程中只能有一个Looper
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// 实例化Looper并存到了sThreadLocal中
sThreadLocal.set(new Looper(quitAllowed));
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
可以看到prepareMainLooper和prepare都调用了prepare(boolean quitAllowed)
方法,区别是主线程的消息队列不能退出。prepare(boolean quitAllowed)
方法实例化了Looper,Looper的构造中实例化了消息队列,保存了当前线程。prepare(boolean quitAllowed)
中将Looper实例保存到了sThreadLocal中,sThreadLocal是一个ThreadLocal(线程本地变量),作用是每个线程中的sThreadLocal存的Looper都是属于自己的,但他们都是存在了同一个变量sThreadLocal中。关于ThreadLocal的使用这里不做详细讲解,有时间在单独分析,先挖个坑。。。
我们调用了prepareMainLooper或者prepare后,需要调用Looper.loop()
启动消息循环,下面看Looper.loop()
做了什么:
#代码块6
// 拿到属于当前线程的Looper
public static Looper myLooper() {
return sThreadLocal.get();
}
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();
// 起了一个死循环,注意是死循环
for (;;) {
// 看官方的注释 :might block 这里会阻塞,也就是说消息队列是个阻塞队列
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
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
// 从消息队列中取出来消息,调用了他的targer,看前面的 代码块3,它的target就是发送它的那个handler
msg.target.dispatchMessage(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.recycle();
}
}
loop()
方法就是在一个死循环中一直从消息队列中取消息,没有消息就会阻塞。取到了消息就会调用msg.target.dispatchMessage(msg)
,最后回收消息msg.recycle()
。
下面看dispatchMessage
方法干了啥:
回到Handler中
#代码块7
public void dispatchMessage(Message msg) {
// 首先判断msg的callback是否为空,我们常用的时候是没有给Message设置过callback的,所以这里大部分情况都是null
if (msg.callback != null) {
handleCallback(msg);
} else {
// 如果Message的callback为空了就会判断Handler的Callback是否为空,大家可以回到 代码块1 中看到我们平时实例化handler的时候调用的是无参数的构造函数,也就是调用了 代码块1 中的第二个构造函数,mCallback也是null所以这里也不会走
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
// 上面都不会走,就到这了,这个方法相信大家都很熟悉了吧,就是我们实例化handler的时候复写的方法
handleMessage(msg);
}
}
整体的流程就是Handler负责把消息添加到队列,Looper中不断取消息处理。