Looper.prepare ()
既然是研究Handler吼和,我們先看看我們常用的Handler的構(gòu)造函數(shù),平時我們都是使用的第一個構(gòu)造洛口,而第一個構(gòu)造會再調(diào)用下面的構(gòu)造函數(shù)影兽,我們看到里面有一個Looper.myLooper()方法,并賦值給成為Handler的成員變量
public Handler(Callback callback) {
this(callback, false);
}
public Handler(Callback callback, boolean async) {
...
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
Looper.myLooper()非常簡單舰始,僅僅是從ThreadLocal類中去get一個Looper對象崇棠,我們繼續(xù)找是在哪里設(shè)置進去的
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
還記得我們在使用HandlerThread的時候需要調(diào)用Looper.prepare嗎?就是為了初始化一個looper保存到當前線程中丸卷,方便Handler的構(gòu)造能使用Looper.myLooper()獲取到當前線程的Looper對象枕稀,并且從上面的構(gòu)造函數(shù)來看,Looper.prepare()的調(diào)用時機應(yīng)該是優(yōu)先于Handler的初始化時機
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");
}
// set方法會將當前ThreadLocal對象作為key谜嫉,looper作為value保存到當前線程中萎坷,
// 由于當前的ThreadLocal是Thread的成員變量,我們只需要在set的線程調(diào)用
// Looper.myLooper就可以獲取到我們之前已經(jīng)初始化好的looper對象
sThreadLocal.set(new Looper(quitAllowed));
}
當應(yīng)用初始化完成后沐兰,已經(jīng)幫我們在主線程中保存好了一個Looper的事例哆档,所以,由于是在同一個線程住闯,Handler能調(diào)用Looper.myLooper獲取到之前保存的Looper對象并且綁定到我們自己的的Handler中
那么問題來了瓜浸,這個主線程的Looper對象是什么時候設(shè)置進去的呢?比原?插佛?
思考:activity的生命周期以及ui更新都是依賴于handler通知,那么主線程Looper的初始化時機一定非常非常早量窘,一個app的入口位于ActivityThread.java的main方法朗涩,我們看看是不是在這里面初始化的呢?
public static void main(String[] args) {
...
Looper.prepareMainLooper();
...
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();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
我們看到了一個非嘲蟾模可疑的函數(shù)Looper.prepareMainLooper(),這個就是初始化主線程Looper的方法谢床,我們在點進去看這個方法
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
果然,這里調(diào)用了Looper的prepare方法去初始化了一個Looper并保存了起來厘线,而且识腿,還把這個Looper賦值給了sMainLooper變量,Looper中有個getMainLooper返回的就是這個sMainLooper造壮,這也就是使用 Looper.getMainLooper() == Looper.myLooper()來判斷是否是主線程的由來
總結(jié)
在app啟動時渡讼,系統(tǒng)會調(diào)用Looper.prepareMainLooper()以sThreaLocal為key骂束,Looper為value保存到主線程中,而我們新建主線程Handler的時候成箫,Handler的構(gòu)造函數(shù)會調(diào)用Looper.myLooper從sThreadLocal中g(shù)et出一個Looper展箱,因為為同一個線程,而sThreadLocal又是同一個變量蹬昌,自然能正確的獲取到在ActivityThread.java中初始化好的全局唯一的Looper對象了混驰,而在希望創(chuàng)建一個跑在其他線程的Handler的時候,我們并沒有事先將這個線程的Looper給保存到當前線程中中皂贩,所以需要調(diào)用Looper.prepare來初始化