android中Looper Handler
关于Looper, 一般比较关注的两个方法:
(1)prepare(): 创建Looper,赋值MessageQueue和Thread
(2)loop():开启一个死循环,来不断的遍历MessageQueue中的消息队列,逐个取出Message通过调用msg.target.dispatchMessage 来依次处理这些消息。(其实,从Handler的源码中我们可以知道这个msg.targe 就是Handler, 所以这个dispatchMessage方法就是Handler的dispatchMessage)。
下面是prepare 和 loop 的源码。
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();
}
public static void loop() {
...
for(;;){
...
msg.target.dispatchMessage(msg);
...
}
...
}
提到Looper一般和之相关的就要提提Handler了。
提到Handler立马一系列都要出来:
(1)Handler :负责发送和处理消息。
(2)Message: 消息(被发送和被处理的一坨)
(3)MessageQueue :存放消息的队列
(4)Looper :从MessageQueue中取Message交给Handler来处理
上面说的太简单了,,,,,嗯, 那看 “细” 的。。。跟一下源码就好,其他的事情我也做不来。
(1)怎样发送、存消息?
我们可以跟一下Handler的sendMessage, 会发现发送消息最终调的都是这个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);
}
看到最终调的是enqueueMessage, 那就看下:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
// 这个千万不要忽略,后面还会出现。如果你没注意到它,后面取出处理消息的时候可能会看不懂。
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
// 最终调用的是MessageQueue的enqueueMessage 方法, 这个方法最终是把Message按照一定的规则放到MessageQueue这个队列中。
return queue.enqueueMessage(msg, uptimeMillis);
}
后面不跟了, MessageQueue中的enqueueMessage就是具体的存放规则算法实现。 感兴趣的可以看看。 贴在这里没啥意思,我们主要是要先有个整体流程的概念。
(2)怎样取出消息并处理 ?
上边说了Looper的loop方法就是一个死循环, 循环内部就是调用messageQueue的next方法来获取Message,然后调用msg.target.dispatchMessage 方法。
上边又说了(哈哈哈)msg.target 其实就是Handler。你可以返回去看Handler的enqueueMessage方法源码。
所以,处理消息最终调的是Handler的dispatchMessage 方法。那我们就来看看这个方法:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
应该很容易看出来,这里最终调的就是 handleMessage , 这个方法我们应该非常非常熟吧。 。 。
问题来了,
(1)为什么Handler能够完成线程间通信?
假设Handler所在的线程为 t1, 另外一个线程是t2。 t2要发送一个Message给t1。
通过源码我们能够知道Handler持有Looper以及MessageQueue的引用。 而Looper持有MessageQueue。 发送消息的时候,在t2的run中我们会调用Handler的sendMessage, 最终会经过MessageQueue的enquequMessage 将消息放入到MessageQueue中,而这个MessageQueue是t1持有的(也可以说持有的引用), 这个很关键。。。 其实,这个时候Message已经在t1“控制的范围”了,这里已经完成了线程间通信。
(2)非主线程使用Handler的时候要自己来调用Looper.prepare()和Looper.loop ()。 那日常中我们在主线程(UI线程)中使用Handler的时候为什么不用自己来处理Handler?
那就看下ActivityThread, 有点牛逼,是不是。。。。 哈哈哈
为什么看这个 , 因为他里边有个main()方法,是整个程序的入口方法。这里边 有想过主线程的Looper操作。请看:
public static void main(String[] args) {
...
// 这里就创建了住线程的Looper
Looper.prepareMainLooper();
...
// 开启了主线程的Looper循环, 然后所有的 用户点击、滑动等事件都以一个一个的Message到MessageQueue中等待处理。
Looper.loop();
...
}
问题:
上边说了Looper.loop() 内部开启了一个死循环, 那为什么这在主线程中这么玩不会ANR?
为什么?
为什么?
那就先看下ANR的原因:
(1)事件没有机会被处理
(2)当前事件的处理耗时太长
常见的: Activity类(5s)KeyDispatchTimeOut, 广播类(10s) BroadcastTimeOut,服务类(20s)ServiceTimeOut
知道了ANR的原因再对比上边的loop死循环就能知道为什么不了。loop中的死循环是不断的从MessageQueue中取出Message进行处理, 如果没有可以被处理的Message线程会进入休眠(阻塞状态),如果再次有新的事件的时候他会从休眠的状态被唤醒。 它是死循环, 但,并没有阻塞事件的处理并没有阻塞事件的处理并没有阻塞事件的处理!
有错误欢迎指出。