Before:
Looper中用到ThreadLocal以及MessageQueue,不熟悉的可以先简单了解下;
Android开发中时常遇到一下错误:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
下面就来了解下Looper这个类:
public final class Looper {
//显然,在不同线程会存有互不干扰的Looper实例
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<>();
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new android.os.Looper(quitAllowed));
}
public static void loop() {
final android.os.Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // 若没有消息则阻塞在这里
if (msg == null) {
return;
}
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
msg.target.dispatchMessage(msg);//分发消息
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
msg.recycleUnchecked();
}
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
}
分析
- 先讲2个故事:
故事1:小明没有零花钱了,又不敢向爸爸妈妈,就想起了他奶奶。他奶奶家和他家距离不远也就几百米,于是他就到他奶奶家去了,但是小明奶奶家里没有现金了,而奶奶又年纪大了不方便去取钱,就打电话给银行要求银行送钱上门,但是银行工作人员办事效率不高,半天都没有送来,于是着急的小明只能空手而返了;过了一会他又去奶奶家看钱有没有送过来,结果银行工作人员还没有过来,小明只能再次空手而返......就这样不断来来回回去奶奶家看钱有没有送过来;
故事2:小红和小明一样没有零花钱却又不敢向爸爸妈妈要,也去找奶奶要;小红第一次去奶奶家,奶奶发现家里没有现金了,就打电话给银行要求送钱上门,而小红则陪着奶奶在家里等银行工作人员送前上门,奶奶心疼小红,不断打电话催银行快点快点;就这样小红每次去奶奶家要零花钱都是等拿到钱了再离开;
暂且不管上述故事剧情如何,其中小明是不管奶奶在不在家,去了就回来,有钱就拿钱,没钱就空手回家,而小红是去了就拿到钱才回来;回到Looper上来,
loop
方法就像是小红,而奶奶则是MessageQueue
,loop
方法调用MessageQueue
的next
方法,若next
方法没有东西可返回就一直等着,并且不断询问有没有新消息过来;要在新线程中使用
Looper
,需要初始化Looper
,因为Looper
对象是保存在ThreadLocal
上的,所以在每个线程上都需要重新初始化,并且不能重复初始化;开启消息循环需要调用
Looper.loop();
,结束时候别忘了要Looper.myLooper().quit();
退出轮询;