文本产生的前提是我在公司组内做的一次分享,当时列了一大堆的要点,奈何本人口拙,分享的时候该讲的内容没讲明白或者根本就没讲到,原本准备两次讲的东西,半小时就讲完了,效果也不是很好。之后因为各种原因组内分享就中断了,过了很久偶然又看到了这个提纲,就想着写成一篇文章,巩固下Handler的知识。
1.Handler用法
一般来说我们使用Handler都是在子线程中进行了耗时操作,完成之后通知主线程刷新界面,这个时候Handler是创建在主线程中的,或者是我们创建在子线程中指定了Handler的Looper是主线程的Looper,用法如下
Handler handler_main = new Handler(); // 主线程中创建Handler
Handler handler_work = new Handler(Looper.getMainLooper()); // 子线程中创建Handler
都是很简单的操作,但是这并不代表其他线程不能通知子线程做操作,只不过创建子线程的Handler稍微麻烦一点。
Looper.prepare();
Handler handler_work = new Handler();
Looper.loop();
说是麻烦,其实也就多了两行代码,需要注意的是Looper.loop一定要调用,且一定要在最后一行调用。
为什么主线程的Handler和子线程的Handler的创建起来不一样呢?其实原因是主线程的Looper已经被Loop过了,代码就在ActivityThread的main方法中
Looper.prepareMainLooper();
// Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
// It will be in the format "seq=114"
long startSeq = 0;
if (args != null) {
for (int i = args.length - 1; i >= 0; --i) {
if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
startSeq = Long.parseLong(
args[i].substring(PROC_START_SEQ_IDENT.length()));
}
}
}
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
其实从这里我们也可以看出,一个线程是可以又多个Handler的,但是只有一个Looper。
2.ThreadLocal
那么Looper是怎么保持线程中唯一的呢?
这就要提到ThreadLocal这个类了。
我们看一下Looper.prepare这个方法
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
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));
}
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return 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;
}
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
ThreadLocal是Looper类的静态成员,Looper共享,当我们调用prepare方法时,如果能拿到一个Looper就报错,否则就创建一个Looper存进去,从这里可以看出,当我们多次调用prepare方法是会抛出异常的。
这里我们就从一个正常的流程调用prepare分析,所以会调用setInitialValue方法,这个方法里给Thread创建了ThreadLocalMap对象,这个对象里存的对象是Looper,但是很可惜,此时的value对象是null,也就是initialValue方法返回的是一个null,而get方法在这里是直接将这个null返回了,所以会走到set方法里,而set方法的参数是直接创建了的一个Looper对象,也就是说Looper是在Looper调用prepare的时候存在Thread的ThreadLocalMap成员变量中的,这就保证了Looper在线程中的唯一。