“说一下handler机制”,这句话面试的时候被问过无数次。但是到底要怎么说,网上却没有一个标准答案,很多人洋洋洒洒一大篇加各种图,实在让人望而生畏,你是让我面试的时候背这么一大篇吗?
其实真的没有那么复杂,干货上前,标准答案:
Handler机制主要由Handler,Looper,MeesageQueue组成。
Looper在程序启动时即创建并不断的在循环,直到Handler有消息发送到MessageQueue时,
Looper取出消息且回调给Handler来处理。
怎么样,洋洋洒洒一大篇看不懂,这么几句话,是不是简单多了?
什么,你说不够深入?
好吧,那我们来深入一下,《How to read a book》讲,一定要提出问题,那我们就来深入的提出几个问题:
1.Looper是个什么玩意,它是怎么创建的?它是什么时候开始循环的?
2.Handler是怎么把发送消息让Looper知道的?
3.Looper又是怎样取出消息且回调给Handler来处理的?
在这里,我们必须阅读一下源码了,我们来看这三个主要组成的其一Looper类,打开代码,是不是很长一大片不知道怎么入手?哎呀好困难怎么办。答案是,一点也不困难,因为我们阅读源码,并不是一行一行读,而是只要看核心方法就够了,什么是核心方法呢?Looper有俩个,prepare(),这个单词的意思是准备;还有一个loop(),这个单词的意思是循环。
我们来看perpare()
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
final MessageQueue mQueue;
final Thread mThread;
public static void prepare() {
prepare(true);
}
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));
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
是的没有错,就这些了,我们可以看到它做了三件事情:
第一、“sThreadLocal.set(new Looper(quitAllowed));” 把new出来的Looper给塞到ThreadLocal里面,我们不难理解ThreadLocal就是一个类似HashMap的东东;
第二、“ mQueue = new MessageQueue(quitAllowed);” new了一个MessageQueue;
第三、“mThread = Thread.currentThread();” 获取当前线程的引用。
接下来是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;
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);
} finally {
}
msg.recycleUnchecked();
}
}
把不重要的代码删掉,是不是一目了然了,已经不用多解释了吧?
我们再来看一个类,ActivityTread的main[]方法,这个地方是程序启动时就会调用的
public static void main(String[] args) {
Looper.prepareMainLooper();
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
class Looper{
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
}
一目了然,也就是说,程序启动时,先prepare() new出来一个Looper,并且把它塞到ThreadLocal里面,以后在同一个线程要用的时候都从里面拿,避免创建多个Looper,然后就开始了loop(),死循环之路,也就是说程序无时无刻不在loop(),然后msg=null的时候,return,直到发现有了msg,msg.target.dispatchMessage(msg);交给msg的target,也就是handler来处理。
我们再来看下Handler的源码,我们先看Handler的构造函数
public Handler(Callback callback, boolean async) {
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
}
Looper.myLooper,正是我们刚才说的,从ThreadLocal里面拿出本线程已有的Looper,然后MessageQueue,也是原来Looper里面的那个MessageQueue,接下来是Handler发送消息的方法,sendMessageAtTime
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) {
return queue.enqueueMessage(msg, uptimeMillis);
}
不难理解,Handler并没有真正意义的去“发送”,而是把消息放到了MessageQueue中而已。
最后,我们来看下Handler如何处理的消息,dispatchMessage
public void handleMessage(Message msg) {
}
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
handleMessage(msg);
}
还记不记得,Loop.loop()中,一旦发现MessageQueue有值,就会调用msg.target.dispatchMessage(msg);走的就是这里啦,还记不记得我们平时写Handler的时候,一般都是这样
Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
}
};
重写的就是上面这个方法啦,至此,我们来回顾一下上面三个问题:
1.Looper是个什么玩意,它是怎么创建的?它是什么时候开始循环的?
2.Handler是怎么发送消息让Looper知道的?
3.Looper又是怎样取出消息且回调给Handler来处理的?
如果对照源码仔细看了本文,相信这几个问题已经不难啦,而且你也学会了如何真正的阅读源码,那就是抓住主线而忽略掉不重要的部分,如果对你有帮助,点个喜欢吧!
网友评论