然后呢,再把自己变成线程的局部变量 static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); ··· sThreadLocal.set(new Looper(quitAllowed)); 这样它们就关联起来了
首先看下prepare()的源码,注意到sThreadLocal,Looper正是通过ThreadLocal来获取到当前线程的looper对象的。下面讲下ThreadLocal类的特性:
ThreadLocal是线程内部的数据存储类,当使用ThreadLocal维护变量的时候,它会为每个使用该变量的线程提供一个独立的变量副本,这个变量副本是该线程独有,不受其他线程影响。
因此当Looper的prepare()中调用
sThreadLocal.get()时,就获取到了当前线程的一个独有的Looper对象,即在在当前线程关联了一个Looper对象,Looper的实现正是巧妙利用了Threadlocal的特性来实现的,避免了去使用哈希表来维护不同线程及其对应Looper的映射关系。
参考:
《Android开发艺术探索》p375
彻底理解ThreadLocal
/** Initialize the current thread as a looper. * This gives you a chance to create handlers that then reference * this looper, before actually starting the loop. Be sure to call * {@link #loop()} after calling this method, and end it by calling * {@link #quit()}. */ 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)); }
/** * Sets the value of this variable for the current thread. If set to * {@code null}, the value will be set to null and the underlying entry will * still be present. * * @param value the new value of the variable for the caller thread. */ public void set(T value) { Thread currentThread = Thread.currentThread(); Values values = values(currentThread); if (values == null) { values = initializeValues(currentThread); } values.put(this, value); }
1.Looper和当前线程的关联表现为Looper的mThread成员变量被赋值为当前线程 private Looper(boolean quitAllowed) { //新建消息队列 mQueue = new MessageQueue(quitAllowed); //获得当前线程 mThread = Thread.currentThread(); } 2.当前线程和Looper的关联表现为Thread的localValues成员变量被赋值 这个变量用于保存键值对,对于Android消息机制来说,键就是ThreadLocal实例,值就是Looper实例。 使用ThreadLocal还保证了一个线程只能有一个Looper, 因为prepare()实现中先取当前线程取Looper实例,当没有取到时才新建Looper实例。 private static void prepare(boolean quitAllowed) { //如果当前线程已经有Looper则抛出异常 if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } //将Looper实例赋值给当前线程的localValues成员变量 sThreadLocal.set(new Looper(quitAllowed)); }