一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第18天,点击查看活动详情。
从Looper.java代码分析一下:
// sThreadLocal.get() will return null unless you've called prepare().
// 用ThreadLocal存储Looper,除非调用prepare(),否则的话sThreadLocal.get()会返回null
// ThreadLocal自身有一个ThreadLocalMap,来管理所有线程对应的变量
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
//在prepare里面创建Looper
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//创建Looper,执行set()
sThreadLocal.set(new Looper(quitAllowed));
}
//获取当前的Looper
public static @Nullable Looper myLooper() {
//通过sThreadLocal.get()获取
return sThreadLocal.get();
}
从ThreadLocal.java代码分析一下:
public T get() {
//获取当前线程
Thread t = Thread.currentThread();
//获取当前线程对应的map
ThreadLocalMap map = getMap(t);
if (map != null) {
//从线程对应的map里面取变量值
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
ThreadLocalMap getMap(Thread t) {
//threadLocals是线程的变量
return t.threadLocals;
}
前面分析到,Looper.myLooper()内部是通过sThreadLocal.get()来返回Looper的,在get()方法内,会先获取到当前线程,然后获取到线程对应的map,最后从map中取出对应的value。
public void set(T value) {
//获取当前线程
Thread t = Thread.currentThread();
//获取当前线程对应的map
ThreadLocalMap map = getMap(t);
if (map != null)
//向线程对应的map里面给变量赋值
map.set(this, value);
else
//首次赋值时需要创建map
createMap(t, value);
}
void createMap(Thread t, T firstValue) {
//对当前线程的threadLocals进行赋值
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
前面分析到,Looper.prepare()内部是通过sThreadLocal.set(new Looper())来存储Looper的,在set()方法内,会先获取到当前线程,然后获取到线程对应的map,如果为null,就创建map,然后存入只;不为null,就直接更新map的值即可。
看一下getMap(t)取出的threadLocals是从何而来?如何确保Looper的唯一性?
//Thread.java
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocal通过获取当前线程中的values属性,从而实现了每个单独线程的信息绑定。在Android的消息机制中,Looper便是采用ThreadLocal作为存储结构,所以looper对象的存储只会在当前线程中,子线程若是使用消息机制的话,必须调用Looper.prepare()方法来在线程中新建一个Looper的对象。