从HandlerThread源码理清handler、looper与messageQueue之间的关系
2017-04-05 17:49
573 查看
前端时间看到一篇关于HandlerThread 的介绍博文,感觉写的不错;再由于近段时间遇到的一个面试题:looper是如何与线程绑定到一起的?当时回答的很不流畅,因此回去之后又跟着源码分析了一边这三者之间的关系,并以此记录下来(sdk以Android-24为例)。
首先看一段简短的代码
由于getMap(t)==null,因此当前Thread会为自己的threadLocals作一个初始化一个ThreadLocalMap,键就是当前的ThreadLocal,firstValue为null。ThreadLocalMap的作用类似于Map存放键值对。
由于sThreadLocal.get()得到的值为空,因此会sThreadLocal.set(new Looper(quitAllowed)),
再通过new Handler(handlerThread.getLooper())就得到了和当前线程Looper关联的Handler。
到此,与此Thread关联的Looper、messageQueue、Handler就此登场了。看看他们两的类图,
下面上重点:looper是如何轮询的?看 Looper.loop();
从for开始看,它也是一个for循环,每次循环都会nativePollOnce一次(它的作用暂时不知),然后找寻msg,找到则返回,如果messageQueue为空则调用next()方法的线程会一直在此处for循环。一个new的新线程MessageQueue中 mMessages是null,所以线程会一直循环,直到Handler send一个message后,mMessages才不会为空。
一句话总结就是:Thread一直在调用Looper的for循环,而Looper的for循环则一直在调用Messagequeue的for循环,即Thread一直在调用MessageQueue的for循环。
最后说明下UI线程,它也是通过调用Looper.prepareMainLooper()和Looper.looper来实现消息轮询的,具体可以看看ActivityThread的main方法实现。
首先看一段简短的代码
HandlerThread handlerThread = new HandlerThread("hai"); handlerThread.start(); Handler handler = new Handler(handlerThread.getLooper()) { @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }; handler.sendEmptyMessage(1);代码的功能就是一个系统已经定义好的一个thread,new出来之后启动,然后拿到这个thread 的handler,通过handler发送消息,thread里的looper接收到消息后把消息交给handler处理。ok!代码片段解释到此结束,下面开始分析HandlerThread是如何实现Android系统的handler-looper消息循环机制。
public class HandlerThread extends Thread { int mPriority; int mTid = -1; Looper mLooper; public HandlerThread(String name) { super(name); mPriority = Process.THREAD_PRIORITY_DEFAULT; }由上看出HandlerThread继承Thread,即它就是一个自定义的Thread。然后handlerThread.start()后线程启动,执行run方法。其实它和自new线程然后在run方法中调用Looper.prepare,Looper.loop 的实现是一个道理
@Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; }且看Looper.prepare(),sThreadLocal是Looper类加载时就初始化的一个对象
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)); }由sThreadLocal.get()进去
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) return (T)e.value; } return setInitialValue(); }由于新new出来的线程的threadLocals没初始化,所以getMap(t)返回空,因而执行setInitialValue(),
private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; }
void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
由于getMap(t)==null,因此当前Thread会为自己的threadLocals作一个初始化一个ThreadLocalMap,键就是当前的ThreadLocal,firstValue为null。ThreadLocalMap的作用类似于Map存放键值对。
由于sThreadLocal.get()得到的值为空,因此会sThreadLocal.set(new Looper(quitAllowed)),
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }当前线程中new的Looper中初始化了一个MessageQueue和保存了对当前线程的引用。
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }set(T value)的作用就是把new出来的Looper保存到当前Thread 的 threadLocals变量中。
再通过new Handler(handlerThread.getLooper())就得到了和当前线程Looper关联的Handler。
到此,与此Thread关联的Looper、messageQueue、Handler就此登场了。看看他们两的类图,
下面上重点:looper是如何轮询的?看 Looper.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; // 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 (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; }Looper通过一个for循环不断的调用queue.next()取message,(这里先说明下,queue.next()不会返回空,除非线程正在退出)
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(); } 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; } } else { // No more messages. nextPollTimeoutMillis = -1; } // Process the quit message now that all pending messages have been handled. if (mQuitting) { dispose(); return null; } // If first time idle, then get the number of idlers to run. // Idle handles only run if the queue is empty or if the first message // in the queue (possibly a barrier) is due to be handled in the future. if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) { pendingIdleHandlerCount = mIdleHandlers.size(); } if (pendingIdleHandlerCount <= 0) { // No idle handlers to run. Loop and wait some more. mBlocked = true; continue; }
从for开始看,它也是一个for循环,每次循环都会nativePollOnce一次(它的作用暂时不知),然后找寻msg,找到则返回,如果messageQueue为空则调用next()方法的线程会一直在此处for循环。一个new的新线程MessageQueue中 mMessages是null,所以线程会一直循环,直到Handler send一个message后,mMessages才不会为空。
一句话总结就是:Thread一直在调用Looper的for循环,而Looper的for循环则一直在调用Messagequeue的for循环,即Thread一直在调用MessageQueue的for循环。
最后说明下UI线程,它也是通过调用Looper.prepareMainLooper()和Looper.looper来实现消息轮询的,具体可以看看ActivityThread的main方法实现。
相关文章推荐
- android开发步步为营之79:通过源码分析Looper,Handler,MessageQueue之间的关系
- android的消息处理机制(图+源码分析)——Thread,Looper,MessageQueue,Message,Handler之间的关系
- 从源码中分析Handler, Looper, Message, MessageQueue之间的关系
- 手把手带你从源码的角度全面理解Handler、Looper、MessageQueue之间的关系
- [图解法结合源码]理解、记忆Handler、Looper、MessageQueue之间的关系
- Message、Handler、MessageQueue、Looper之间关系图文总结
- 源码分析Handler 、 Looper 、Message之间的关系
- 从源码中深入学习Handler,HandlerThread,MessageQueue,Looper。
- Message、Handler、MessageQueue、Looper之间的关系
- Android应用开发多线程基础之Handler,Looper,Message,MessageQueue,Runnable之间的关系
- 解析Handler,MessageQueue,Message,Looper之间的关系
- Thread,Looper,Handler,Message,MessageQueue之间的关系
- Android笔记-MultiThreading in Android(1)-Thread,Looper,Handler,Message,MessageQueue之间的关系
- Android笔记-MultiThreading in Android(1)-Thread,Looper,Handler,Message,MessageQueue之间的关系
- Thread,Looper,Handler,Message,MessageQueue之间的关系
- 从Android源码角度对Handler,MessageQueue,Looper之间消息传递工作原理的理解
- Android面试题 请解释下单线程模型中Message、Handler、MessageQueue、Looper之间的关系
- 彻底搞定Looper,Handler,Message,MessageQueue,和Thread之间的关系
- 单线程模型中Message、Handler、MessageQueue、Looper之间的关系
- Android笔记-MultiThreading in Android(1)-Thread,Looper,Handler,Message,MessageQueue之间的关系