HandlerThread源碼分析

概要介紹

HandlerThread是一種特殊的Thread叶摄,也就是有Looper的thread狈究,既然有Looper的話碗淌,那我們就可以用此Looper來(lái)創(chuàng)建一個(gè)Handler,從而實(shí)現(xiàn)和它的交互抖锥。比如你可以通過(guò)與它關(guān)聯(lián)的Handler對(duì)象在UI線程中發(fā)消息給它處理亿眠。HandlerThread一般可以用來(lái)執(zhí)行某些background的操作,比如讀寫文件磅废、進(jìn)行一些計(jì)算(在此HandlerThread而非UI線程中)纳像。既然還是一個(gè)Thread系瓢,那么和一般的Thread一樣溶浴,也要通過(guò)調(diào)用其start()方法來(lái)啟動(dòng)它。它只是Android替我們封裝的一個(gè)Helper類,其源碼相當(dāng)簡(jiǎn)潔荆忍,有一些經(jīng)典的標(biāo)準(zhǔn)寫法禁灼,我們一起來(lái)看看昵仅。

源碼分析

和以往一樣退渗,我們先來(lái)看看其字段和構(gòu)造函數(shù):

    int mPriority; // 線程優(yōu)先級(jí)
    int mTid = -1; // 線程id
    Looper mLooper; // 與此線程關(guān)聯(lián)的Looper

    public HandlerThread(String name) { // 提供個(gè)名字,方便debug
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT; // 沒(méi)提供犀勒,則使用默認(rèn)優(yōu)先級(jí)
    }
    
    /**
     * Constructs a HandlerThread.
     * @param name
     * @param priority The priority to run the thread at. The value supplied must be from 
     * {@link android.os.Process} and not from java.lang.Thread.
     */
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority; // 使用用戶提供的優(yōu)先級(jí)屎飘,取Process.java中定義的常量
    }

代碼很簡(jiǎn)單,相關(guān)的分析都直接寫在代碼的注釋里了贾费,值得注意的是這里的priority是基于Linux優(yōu)先級(jí)的钦购,而不是Java Thread類里的MIN_PRIORITY,NORM_PRIORITY铸本,MAX_PRIORITY之類肮雨,請(qǐng)注意區(qū)分(其實(shí)認(rèn)真閱讀方法的doc即可)遵堵。

接下來(lái)看看此類的3個(gè)關(guān)鍵方法:

    /**
     * Call back method that can be explicitly overridden if needed to execute some
     * setup before Looper loops.
     */
    protected void onLooperPrepared() {
        // callback方法箱玷,如果你愿意可以O(shè)verride放自己的邏輯;其在looper開(kāi)始前執(zhí)行
    }

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare(); // 此方法我們前面介紹過(guò)陌宿,會(huì)創(chuàng)建與線程關(guān)聯(lián)的Looper對(duì)象
        synchronized (this) { // 進(jìn)入同步塊锡足,當(dāng)mLooper變的可用的使用,調(diào)用notifyAll通知其他可能block在當(dāng)前對(duì)象上的線程
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority); // 設(shè)置線程優(yōu)先級(jí)
        onLooperPrepared(); // 調(diào)用回調(diào)函數(shù)
        Looper.loop(); // 開(kāi)始loop
        mTid = -1; // reset為invalid值
    }
    
    /**
     * This method returns the Looper associated with this thread. If this thread not been started
     * or for any reason is isAlive() returns false, this method will return null. If this thread 
     * has been started, this method will block until the looper has been initialized.  
     * @return The looper.
     */
    public Looper getLooper() {
        if (!isAlive()) { // 如果線程不是在alive狀態(tài)則直接返回null壳坪,有可能是你忘記調(diào)start方法了舶得。。爽蝴。
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) { // 進(jìn)入同步塊沐批,當(dāng)條件不滿足時(shí)無(wú)限等待,
                try {                              // 直到mLooper被設(shè)置成有效值了才退出while(當(dāng)然也可能是線程狀態(tài)不滿足)蝎亚;
                    wait();                        // run方法里的notifyAll就是用來(lái)喚醒這里的
                } catch (InterruptedException e) { // 忽略InterruptedException
                }
            }
        }
        return mLooper; // 最后返回mLooper九孩,此時(shí)可以保證是有效值了。
    }

當(dāng)你new一個(gè)HandlerThread的對(duì)象時(shí)記得調(diào)用其start()方法发框,然后你可以接著調(diào)用其getLooper()方法來(lái)new一個(gè)Handler對(duì)象躺彬,最后你就可以利用此Handler對(duì)象來(lái)往HandlerThread發(fā)送消息來(lái)讓它為你干活了。
  
最后來(lái)看2個(gè)退出HandlerThread的方法梅惯,其實(shí)對(duì)應(yīng)的是Looper的2個(gè)退出方法:

    /**
     * Quits the handler thread's looper.
     * <p>
     * Causes the handler thread's looper to terminate without processing any
     * more messages in the message queue.
     * </p><p>
     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
     * For example, the {@link Handler#sendMessage(Message)} method will return false.
     * </p><p class="note">
     * Using this method may be unsafe because some messages may not be delivered
     * before the looper terminates.  Consider using {@link #quitSafely} instead to ensure
     * that all pending work is completed in an orderly manner.
     * </p>
     *
     * @return True if the looper looper has been asked to quit or false if the
     * thread had not yet started running.
     *
     * @see #quitSafely
     */
    public boolean quit() {
        Looper looper = getLooper(); // 注意這里是調(diào)用getLooper而不是直接使用mLooper宪拥,
        if (looper != null) {        // 因?yàn)閙Looper可能還沒(méi)初始化完成,而調(diào)用方法可以
            looper.quit();           // 等待初始化完成铣减。
            return true;
        }
        return false;
    }

    /**
     * Quits the handler thread's looper safely.
     * <p>
     * Causes the handler thread's looper to terminate as soon as all remaining messages
     * in the message queue that are already due to be delivered have been handled.
     * Pending delayed messages with due times in the future will not be delivered.
     * </p><p>
     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
     * For example, the {@link Handler#sendMessage(Message)} method will return false.
     * </p><p>
     * If the thread has not been started or has finished (that is if
     * {@link #getLooper} returns null), then false is returned.
     * Otherwise the looper is asked to quit and true is returned.
     * </p>
     *
     * @return True if the looper looper has been asked to quit or false if the
     * thread had not yet started running.
     */
    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

通過(guò)代碼我們可以看到其內(nèi)部都是delegate給了Looper對(duì)象她君,而Looper我們?cè)谇懊嬉步榻B過(guò)了,感興趣的同學(xué)可以翻看前面的分析或者查看這2個(gè)方法的doc葫哗,寫的都很詳細(xì)犁河。
  至此這個(gè)簡(jiǎn)單的Handy class就算分析完畢了鳖枕。在實(shí)際的開(kāi)發(fā)中,如果你只是要做某些后臺(tái)的操作(短暫的桨螺,比如把某些設(shè)置文件load到內(nèi)存中)宾符,而不需要更新UI的話,那你可以優(yōu)先使用HandlerThread而不是AsyncTask灭翔。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末魏烫,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子肝箱,更是在濱河造成了極大的恐慌哄褒,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件煌张,死亡現(xiàn)場(chǎng)離奇詭異呐赡,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)骏融,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門链嘀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人档玻,你說(shuō)我怎么就攤上這事怀泊。” “怎么了误趴?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵霹琼,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我凉当,道長(zhǎng)枣申,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任看杭,我火速辦了婚禮忠藤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘泊窘。我一直安慰自己熄驼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布烘豹。 她就那樣靜靜地躺著瓜贾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪携悯。 梳的紋絲不亂的頭發(fā)上祭芦,一...
    開(kāi)封第一講書(shū)人閱讀 51,590評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音憔鬼,去河邊找鬼龟劲。 笑死胃夏,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的昌跌。 我是一名探鬼主播仰禀,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蚕愤!你這毒婦竟也來(lái)了答恶?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤萍诱,失蹤者是張志新(化名)和其女友劉穎悬嗓,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體裕坊,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡包竹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了籍凝。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片周瞎。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖静浴,靈堂內(nèi)的尸體忽然破棺而出堰氓,到底是詐尸還是另有隱情挤渐,我是刑警寧澤苹享,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站浴麻,受9級(jí)特大地震影響得问,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜软免,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一宫纬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧膏萧,春花似錦漓骚、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至曹锨,卻和暖如春孤个,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背沛简。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工齐鲤, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留斥废,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓给郊,卻偏偏與公主長(zhǎng)得像牡肉,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子淆九,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

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