Looper是Android用来进行线程间通信的,一般是UI线程和工作线程通信,对于很多人最难理解的是JAVA层Handler, Looper, MessageQueue与线程的关系,一旦关系理解了你就明白其中的工作原理了
最重要的准备知识点是ThreadLocal,如果这个不能理解就没法看下文了参考链接http://blog.csdn.net/zdp072/article/details/39155143
一:
形象的描述一下 Looper MessageQueue 与线程的关系:线程好比一艘船,Looper依赖于线程,每个船舱里都有1个Looper,然后这个Looper有1个MessageQueue,Looper会不停的循环看这个MessageQueue有没有消息,如果有消息就会抛给船甲板上的员工(Handler),员工也会把消息丢到它所在船上的MessageQueue里面
包含的知识点如下
1: 也就是1个线程只有1个Looper和MessageQueue,但是这个线程可以有多个Handler
2:Handler sendMessage是往自己所在的线程里面的MessageQueue里面发送消息
3:Looper循环处理的MessageQueue是自己所在线程的
可以看下图参考一下:
到这抛出了一个概念,下面我们可以分析源码来更全面的认识一下:
涉及到的源码目录
\frameworks\base\core\java\android\os\Looper.java
\frameworks\base\core\java\android\os\MessageQueue.java
\frameworks\base\core\java\android\os\Handler.java
\frameworks\base\core\java\android\os\Message.java
从这个Demo分析:
* <pre>
* class LooperThread extends Thread {
* public Handler mHandler;
*
* public void run() {
* Looper.prepare();
*
* mHandler = new Handler() {
* public void handleMessage(Message msg) {
* // process incoming messages here
* }
* };
*
* Looper.loop();
* }
* }</pre>
一:我们先看Looper.java(就是不停的从MessageQueue里面拿消息抛给船板上的Handler)
分析Looper.prepare()做了什么东西
这个sThreadLocal.set(new Looper)是啥意思呢?所以要理解ThreadLocal是干啥的,其实就是ThreadLocal有块Map内存,Key是线程,Value在这是Looper,每次调用sThreadLocal.set()的时候就是更新这个Map集合,Key是线程自己,Value是Looper对象,所以这边保证了1个线程内部只有1个对应的Looper对象
二:看一下Looper的构造函数做了什么
就是创建了一个MessageQueue然后更新变量指向调用改函数所在的线程
三:现在分析Looper.loop()是干啥的了
也就是不停的从线程里面的messgaequeue取消息,然后调用handler的dispatchmsg()
到这Looper就分析结束了内容少关键就是理解ThreadLocal
一:现在开始分析MessageQueue
MessageQueue与Native层MessageQueue其实是两套机制,讲这个前就需要做好Framewok Java层与Native层的MessagqQueue的区别
读者首先得知道我们的Looper 会首先处理Native层的消息然后再处理Java层的消息,那么Native层的消息是怎么处理的呢?这个就看下篇Native 的机制,先看下面这张图有个框架知识
这张图意思是指Java的MessagQueue会通过JNI创建一个Native的MessageQUeue,这个C++版的MessageQueue会创建一个Looper.cpp(C++版的Looper与Java版的Looper没有任何关系两码事),这个Native的Looper是通过Epoll机制去处理Native层的消息,其实Looper.cpp就是Android版的Epoll
继续分析Java层的MessageQueue看一下构造函数
通过JNI创建了Native层的MessageQueue
/**MessageQueue取消息函数*/
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
/**MessageQueue首先处理Native层的消息然后Java层*/
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
这边就是MessageQueue的next()函数返回队列里面的消息
一:下面分析Handler内容
这样你就能明白你每次调用new Handler()的时候它会找到这个线程的looper和messageQueue
然后看handler每次怎么丢消息的
OK 到此Java层结束了