HandlerThread
?在理解了Handler的原理之后借嗽,我們知道在一個子線程中創(chuàng)建一個Handler不能缺少了Looper.prepare()和Looper.loop()兩個方法走敌,具體的原因這里不再贅述呢灶,不熟悉原理的可以先看下另一篇文章Handler的原理解析.
本篇文章主要是講解HandlerThread的使用的胚迫。
?首先HandlerThread是繼承于Thread類的,所以本質(zhì)上HandlerThread就是一個線程,接下來就詳細(xì)的去看一看抬虽,這是怎樣的一個線程略号?
?首先刑峡,先看下它的構(gòu)造函數(shù):
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
//很簡單洋闽,構(gòu)造函數(shù)里只是設(shè)置了該Thread的名稱和優(yōu)先級。
?既然是線程突梦,那么最重要的當(dāng)然是run方法來诫舅,看完了run方法,相信你也就明白HandlerThread的用途了阳似!
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
?怎么樣骚勘,這是不是和我們之前在子線程中創(chuàng)建Handler一樣,首先是Looper.prepare(),接著是new Handler(), 最后是Looper.loop()撮奏。等等俏讹,這里并沒有創(chuàng)建Handler啊畜吊!別急泽疆,我們先一步一步地看看run方法再說為什么沒有創(chuàng)建Handler。
- 首先呢是調(diào)用了Looper.prepaer()玲献,該方法為我們的線程創(chuàng)建了一個唯一的Looper和MessageQueue對象殉疼,具體的創(chuàng)建過程看另一篇文章Handler的原理解析
- 接下來有一個同步鎖的代碼塊,里面獲取到了創(chuàng)建好的Looper對象將其賦值給當(dāng)前的mLooper捌年,然后喚醒了鎖瓢娜。注意這里有一個喚醒線程的操作,既然有喚醒鎖的操作礼预,那么必定有有個地方使線程處于了阻塞的狀態(tài)眠砾,我們看下出現(xiàn)阻塞的地方。
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
?通過查找發(fā)現(xiàn)到一個getLooper()的方法托酸,該方法返回了當(dāng)前線程的mLooper對象褒颈,還記得Looper是在哪里進(jìn)行賦值的嗎?在線程的run方法里励堡,所以當(dāng)線程啟動之后才能創(chuàng)建Looper并賦值給mLooper谷丸,這里的阻塞就是為了等待Looper的創(chuàng)建成功。同時該方法是用Public修飾的应结,說明該方法是提供外部調(diào)用的刨疼,Looper創(chuàng)建成功提供給外部使用。
- 接著我們回到run方法鹅龄,Looper和MessageQueue已經(jīng)創(chuàng)建成功了币狠,接下來就是啟動Looper循環(huán)了(即Looper.loop()),別忘了只有Looper循環(huán)啟動后我們才能時刻觀察著MessageQueue砾层,只要有Message了才能立馬將Message取出來進(jìn)行分發(fā)處理漩绵。
- 在Looper.loop()之前還調(diào)用了一個onLooperPrepared()方法,這個方法是干嘛的呢肛炮? 看代碼可知止吐,只是一個空方法宝踪,在使用HandlerThread時重寫該方法,方便在Looper輪詢消息之前做一些初始化的操作碍扔。
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}
?最后在對象銷毀前瘩燥,調(diào)用下面的方法退出Looper循環(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;
}
?quit方法實(shí)際是調(diào)用MessagQueue的removeAllMessagesLocked,移除所有延遲和非延遲的消息不同,
?quitSafely方法調(diào)用的是removeAllFutureMessagesLocked方法厉膀,該方法只清除延遲的消息,非延遲的消息
還是會進(jìn)行分發(fā)處理二拐。
?HandlerThread分析完啦服鹅,是不是有點(diǎn)蒙,自始至終都沒有出現(xiàn)Handler百新,HandlerThread要怎么用呢企软?
?下面我們就通過一個Demo來說明下HandlerThread是怎么用的?
private WorkHandler mHandler;
private HandlerThread mHandlerThread;
/*Handler存在一個構(gòu)造函數(shù)饭望,傳入一個Looper對象仗哨,Handler的handleMessage獲取的是Looper的MessageQueue中的Message
因此,handleMessage的調(diào)用與Looper對象同屬于一個線程铅辞,這里我們在構(gòu)造時傳入HandlerThread的Looper對象厌漂,
handleMessage運(yùn)行于HandlerThread線程(也就是一個子線程),所以Handler雖然是在住線程創(chuàng)建斟珊,但是它的
handleMessage接收到消息是在HandlerThread線程桩卵,執(zhí)行下代碼可以看到打印出如下log:
D/HandlerThreadDemo: HandlerThread/Demo thread receiver the message from thread: main
log也說明,message由主線程傳遞到了HandlerThread中倍宾。
*/
private class WorkHandler extends Handler {
WorkHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
String str = (String) msg.obj;
Log.d(TAG, Thread.currentThread().getName() + " thread receiver the message from thread: " + msg.obj);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handlerthread_demo);
mHandlerThread = new HandlerThread("HandlerThread/Demo");
mHandlerThread.start();
mHandler = new WorkHandler(mHandlerThread.getLooper());
Message msg = mHandler.obtainMessage();
msg.obj = Thread.currentThread().getName();
mHandler.sendMessage(msg);
}
總結(jié):
- HandlerThread繼承于Thread,本質(zhì)上也是一個線程胜嗓。
- HandlerThread的run方法為本線程創(chuàng)建提供了Looper和MessageQueue對象高职,并開啟了Looper輪詢消息。
- 通過在需要發(fā)送Message的線程中創(chuàng)建Handler辞州,為Handler提供來自HandlerThread的Looper對象怔锌。Handler則能
將消息發(fā)送到HandlerThread上去進(jìn)行處理。
注意:這里Handler不僅僅能在主線程創(chuàng)建变过,在子線程同樣能夠創(chuàng)建埃元,只需要將對應(yīng)的Looper提供給Handler即可,所以HandlerThread
不僅適用于和主線程通信媚狰,同樣適用于和其他子線程通信岛杀。 - 最后需要注意的是在我們不需要這個looper線程的時候需要手動停止掉,即調(diào)用quit()或者quitSafely()崭孤。
- 最后補(bǔ)充一個在實(shí)際開發(fā)過程中使用到HandlerThread的場景:
存在多個耗時的任務(wù)需要放到開啟子線程依次去處理(串行處理任務(wù)),首先类嗤,HandlerThread是一個子線程糊肠,
適合處理耗時的任務(wù),其次遗锣,Handler分發(fā)消息是通過MessageQueue頂部的Message不斷的通過Message的next依次取出
Message货裹,符合任務(wù)的按順序串行處理的要求,所以使用HandlerThread就能完美的解決此需求精偿。