HandlerThread 之簡單理解與使用

HandlerThread 顧名思義就是一種可以使用 Handler 的 Thread恕出。日常開發(fā)中我們經(jīng)常會通過創(chuàng)建一個 Thread 去執(zhí)行任務(wù)礁鲁,有多個任務(wù)就多創(chuàng)建幾個線程實現(xiàn)鞋吉,這時候可能出現(xiàn)線程同步的問題捷兰。不過有時候我們并不需要很強的并發(fā)性农渊,只需保證按照順序地執(zhí)行各個任務(wù)即可泻红,有什么好辦法實現(xiàn)呢告私?第一反應(yīng)想到的可能是通過 Executors.newSingleThreadExecutor() 方法來創(chuàng)建一個 SingleThreadExecutor,來統(tǒng)一所有的任務(wù)到一個線程中承桥,然后按順序執(zhí)行驻粟。其實,除了這個方法之外,HandlerThread 也可以實現(xiàn)蜀撑。

簡單使用

首先創(chuàng)建一個 HandlerThreadActivity

public class HandlerThreadActivity extends BaseActivity {
    
    private static final String TAG = "HandlerThreadActivity";

    private Button mStartBtn;
    private Handler mHandler;
    private HandlerThread mHandlerThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler_thread);
        mStartBtn = findViewById(R.id.start_btn);

        mHandlerThread = new HandlerThread("THREAD_NAME");
        mHandlerThread.start();
        mHandler = new Handler(mHandlerThread.getLooper());

        mStartBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        Log.d(TAG, Thread.currentThread().getId() + " " + String.valueOf((Looper.myLooper() == Looper.getMainLooper())) + " 任務(wù):" + this.hashCode());
                        SystemClock.sleep(3000);
                    }
                });
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandlerThread.quit();
    }
}

快速三擊按鈕挤巡,打印日志如下:


可以發(fā)現(xiàn),三次不同的任務(wù)按開始的順序執(zhí)行酷麦,而且是運行在子線程中矿卑,那到底是怎么實現(xiàn)的呢?

源碼解析

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;
    private @Nullable Handler mHandler;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    
   
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
    
   
    protected void onLooperPrepared() {
    }

    @Override
    public void run() {
        // 獲取線程 id
        mTid = Process.myTid();
        //構(gòu)建一個 Looper
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        //設(shè)置線程優(yōu)先級
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        // Looper 循環(huán)
        mTid = -1;
    }
    
     // 獲取當(dāng)前線程的 Looper沃饶,
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
       
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }


     /**
     * @return a shared {@link Handler} associated with this thread
     * @hide 方法隱藏掉母廷,無法調(diào)用
     */
    @NonNull
    public Handler getThreadHandler() {
        if (mHandler == null) {
            mHandler = new Handler(getLooper());
        }
        return mHandler;
    }

     //線程退出方法,主要是調(diào)用 Looper.quit() 方法糊肤,不然一直在循環(huán)
    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }

    //同上琴昆,不過這個方法會把消息隊列中的已有消息處理完才會安全地退出
    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

    public int getThreadId() {
        return mTid;
    }
}

通讀下來,如果熟悉 Handler 原理的同學(xué)大概就明白 HandlerThread 的機制了:

  • HandlerThread 運行 start() 方法馆揉,回調(diào) run() 方法业舍。
  • 在 run() 方法中通過 Looper.prepare() 來創(chuàng)建消息隊列,并通過 Looper.looper() 方法來開啟消息循環(huán)升酣。
  • 由于 Loop.loop() 是一個死循環(huán)舷暮,導(dǎo)致 run() 也是無線循環(huán),因此當(dāng)我們不需要使用 HandlerThread 的時候噩茄,要調(diào)用它的 quit() 方法或者 quiteSafely() 方法下面。

結(jié)束語

這就是 HandlerThread 的大概原理啦,它在 Android 中的一個具體的使用場景是 IntentService绩聘,有興趣了解 IntentService 的可以點擊這里沥割。
慣例附上--->Demo源碼<---

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市君纫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌芹彬,老刑警劉巖蓄髓,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異舒帮,居然都是意外死亡会喝,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進(jìn)店門玩郊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來肢执,“玉大人,你說我怎么就攤上這事译红≡で眩” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長耻陕。 經(jīng)常有香客問我拙徽,道長,這世上最難降的妖魔是什么诗宣? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任膘怕,我火速辦了婚禮,結(jié)果婚禮上召庞,老公的妹妹穿的比我還像新娘岛心。我一直安慰自己,他們只是感情好篮灼,可當(dāng)我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布忘古。 她就那樣靜靜地躺著,像睡著了一般穿稳。 火紅的嫁衣襯著肌膚如雪存皂。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天逢艘,我揣著相機與錄音旦袋,去河邊找鬼。 笑死它改,一個胖子當(dāng)著我的面吹牛疤孕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播央拖,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼祭阀,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了鲜戒?” 一聲冷哼從身側(cè)響起专控,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎遏餐,沒想到半個月后伦腐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡失都,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年柏蘑,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片粹庞。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡咳焚,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出庞溜,到底是詐尸還是另有隱情革半,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站督惰,受9級特大地震影響不傅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜赏胚,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一访娶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧觉阅,春花似錦崖疤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至割笙,卻和暖如春权烧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背伤溉。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工般码, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人乱顾。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓板祝,卻偏偏與公主長得像,于是被迫代替她去往敵國和親走净。 傳聞我的和親對象是個殘疾皇子券时,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,055評論 2 355