為什么主線程不用調(diào)用 Looper.prepare()

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來初始化

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末栖榨,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子明刷,更是在濱河造成了極大的恐慌婴栽,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辈末,死亡現(xiàn)場離奇詭異愚争,居然都是意外死亡,警方通過查閱死者的電腦和手機挤聘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門轰枝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人檬洞,你說我怎么就攤上這事狸膏。” “怎么了添怔?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵湾戳,是天一觀的道長。 經(jīng)常有香客問我广料,道長砾脑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任艾杏,我火速辦了婚禮韧衣,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘购桑。我一直安慰自己畅铭,他們只是感情好,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布勃蜘。 她就那樣靜靜地躺著硕噩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪缭贡。 梳的紋絲不亂的頭發(fā)上炉擅,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天辉懒,我揣著相機與錄音,去河邊找鬼谍失。 笑死眶俩,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的快鱼。 我是一名探鬼主播颠印,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼攒巍!你這毒婦竟也來了嗽仪?” 一聲冷哼從身側(cè)響起荒勇,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤柒莉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后沽翔,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體兢孝,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年仅偎,在試婚紗的時候發(fā)現(xiàn)自己被綠了跨蟹。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡橘沥,死狀恐怖窗轩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情座咆,我是刑警寧澤痢艺,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站介陶,受9級特大地震影響堤舒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜哺呜,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一舌缤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧某残,春花似錦国撵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至椭豫,卻和暖如春耻瑟,著一層夾襖步出監(jiān)牢的瞬間旨指,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工喳整, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留谆构,地道東北人。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓框都,卻偏偏與公主長得像搬素,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子魏保,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容