為什么需要HandlerThread?
HandlerThread本質(zhì)上就是一個(gè)普通Thread,只不過(guò)內(nèi)部建立了Looper,handlerthread實(shí)質(zhì)上建立了一個(gè)模型,簡(jiǎn)化了像下面這種子線(xiàn)程與子線(xiàn)程之間的通信。
子線(xiàn)程和子線(xiàn)程之間的通信:
public class MainActivity extends AppCompatActivity {
private Handler handler1;
private Handler handler2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new MyThread1().start();
new MyThread2().start();
}
class MyThread1 extends Thread {
@Override
public void run() {
super.run();
Looper.prepare();
handler1 = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
System.out.println("threadName--" + Thread.currentThread().getName() + "messageWhat-" + msg.what);
}
};
try {
sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler2.sendEmptyMessage(2);
Looper.loop();
}
}
class MyThread2 extends Thread {
@Override
public void run() {
super.run();
Looper.prepare();
handler2 = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
System.out.println("threadName--" + Thread.currentThread().getName() + "messageWhat-" + msg.what);
}
};
try {
sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler1.sendEmptyMessage(5);
Looper.loop();
}
}
}
- 調(diào)用Looper類(lèi)的 prepare() 方法可以為當(dāng)前線(xiàn)程創(chuàng)建一個(gè)消息循環(huán),調(diào)用loop() 方法使之處理信息,直到循環(huán)結(jié)束。
- Handler有幾個(gè)構(gòu)造重載,如果構(gòu)造時(shí)不提供Looper類(lèi)對(duì)象參數(shù),會(huì)獲取當(dāng)前線(xiàn)程的Looper對(duì)象,即將當(dāng)前線(xiàn)程的消息循環(huán)作為Handler關(guān)聯(lián)的消息循環(huán)。
- 消息處理機(jī)制中,消息存放在一個(gè)消息隊(duì)列中,而線(xiàn)程圍繞這個(gè)隊(duì)列進(jìn)入一個(gè)無(wú)限循環(huán),直到程序退出。如果隊(duì)列中有消息,線(xiàn)程就會(huì)把消息取出來(lái),并分發(fā)給相應(yīng)的Handler進(jìn)行處理;如果隊(duì)列中沒(méi)有消息,線(xiàn)程就會(huì)進(jìn)入空閑等待狀態(tài),等待下一個(gè)消息的到來(lái)。
HandlerThread的用法
public class MainActivity extends AppCompatActivity {
private HandlerThread myHandlerThread ;
private Handler handler ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//創(chuàng)建一個(gè)線(xiàn)程,線(xiàn)程名字:handler-thread
myHandlerThread = new HandlerThread( "handler-thread") ;
//開(kāi)啟一個(gè)線(xiàn)程
myHandlerThread.start();
//在這個(gè)線(xiàn)程中創(chuàng)建一個(gè)handler對(duì)象
handler = new Handler( myHandlerThread.getLooper() ){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//這個(gè)方法是運(yùn)行在 handler-thread 線(xiàn)程中的 ,可以執(zhí)行耗時(shí)操作
Log.d( "handler " , "消息: " + msg.what + " 線(xiàn)程: " + Thread.currentThread().getName() ) ;
}
};
//在主線(xiàn)程給handler發(fā)送消息
handler.sendEmptyMessage( 1 ) ;
new Thread(new Runnable() {
@Override
public void run() {
//在子線(xiàn)程給handler發(fā)送數(shù)據(jù)
handler.sendEmptyMessage( 2 ) ;
}
}).start() ;
}
@Override
protected void onDestroy() {
super.onDestroy();
//釋放資源
myHandlerThread.quit() ;
}
}
運(yùn)行效果:
/com.app D/handler: 消息: 1 線(xiàn)程: handler-thread
/com.app D/handler: 消息: 2 線(xiàn)程: handler-thread
HandlerThread退出循環(huán)的方法
Looper是通過(guò)調(diào)用loop方法驅(qū)動(dòng)著消息循環(huán)的進(jìn)行: 從MessageQueue中阻塞式地取出一個(gè)消息,然后讓Handler處理該消息,周而復(fù)始,loop方法是個(gè)死循環(huán)方法。那如何終止消息循環(huán)呢?
handlerThread.quit()
或
handlerThread.quitSafely()
- 相同點(diǎn):
將不在接受新的事件加入消息隊(duì)列。無(wú)論是調(diào)用了quit方法還是quitSafely方法只會(huì),Looper就不再接收新的消息。即在調(diào)用了Looper的quit或quitSafely方法之后,消息循環(huán)就終結(jié)了,這時(shí)候再通過(guò)Handler調(diào)用sendMessage或post等方法發(fā)送消息時(shí)均返回false,表示消息沒(méi)有成功放入消息隊(duì)列MessageQueue中,因?yàn)橄㈥?duì)列已經(jīng)退出了。 - 不同點(diǎn)
- 當(dāng)我們調(diào)用Looper的quit方法時(shí),實(shí)際上執(zhí)行了MessageQueue中的removeAllMessagesLocked方法,該方法的作用是把MessageQueue消息池中所有的消息全部清空,無(wú)論是延遲消息(延遲消息是指通過(guò)sendMessageDelayed或通過(guò)postDelayed等方法發(fā)送的需要延遲執(zhí)行的消息)還是非延遲消息。
- 當(dāng)我們調(diào)用Looper的quitSafely方法時(shí),實(shí)際上執(zhí)行了MessageQueue中的removeAllFutureMessagesLocked方法,通過(guò)名字就可以看出,該方法只會(huì)清空MessageQueue消息池中所有的延遲消息,并將消息池中所有的非延遲消息派發(fā)出去讓Handler去處理,quitSafely相比于quit方法安全之處在于清空消息之前會(huì)派發(fā)所有的非延遲消息。
需要注意的是Looper的quit方法從API Level 1就存在了,但是Looper的quitSafely方法從API Level 18才添加進(jìn)來(lái)。
HandlerThread要點(diǎn)
- HandlerThread將loop轉(zhuǎn)到子線(xiàn)程中處理,說(shuō)白了就是將分擔(dān)MainLooper的工作量,降低了主線(xiàn)程的壓力,使主界面更流暢,不阻塞UI線(xiàn)程。
- 處理任務(wù)是串行執(zhí)行,按消息發(fā)送順序進(jìn)行處理。HandlerThread本質(zhì)是一個(gè)線(xiàn)程,在線(xiàn)程內(nèi)部,代碼是串行處理的。
- 對(duì)于網(wǎng)絡(luò)IO操作,HandlerThread并不適合,因?yàn)樗挥幸粋€(gè)線(xiàn)程,每一個(gè)任務(wù)都將以隊(duì)列的方式逐個(gè)被執(zhí)行到,一旦隊(duì)列中有某個(gè)任務(wù)執(zhí)行時(shí)間過(guò)長(zhǎng),那么就會(huì)導(dǎo)致后續(xù)的任務(wù)都會(huì)被延遲處理。
- HandlerThread在不需要使用的時(shí)候需要手動(dòng)的回收掉;
HandlerThread源碼解析
我們通過(guò)
//創(chuàng)建一個(gè)線(xiàn)程,線(xiàn)程名字:handler-thread
myHandlerThread = new HandlerThread( "handler-thread") ;
//開(kāi)啟一個(gè)線(xiàn)程
myHandlerThread.start();
創(chuàng)建和啟動(dòng)HandlerThread.
對(duì)應(yīng)源碼為:
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
其實(shí)我們就是初始化和啟動(dòng)了一個(gè)線(xiàn)程;然后我們看run()方法,可以看到該方法中調(diào)用了Looper.prepare(),Loop.loop();prepare()中創(chuàng)建了一個(gè)Looper對(duì)象,并且把該對(duì)象放到了該線(xiàn)程范圍內(nèi)的變量中(sThreadLocal),在Looper對(duì)象的構(gòu)造過(guò)程中,初始化了一個(gè)MessageQueue,作為該Looper對(duì)象成員變量。
loop()就開(kāi)啟了,不斷的循環(huán)從MessageQueue中取消息處理了,當(dāng)沒(méi)有消息的時(shí)候會(huì)阻塞,有消息的到來(lái)的時(shí)候會(huì)喚醒。
接下來(lái),我們創(chuàng)建了一個(gè)handler
handler = new Handler( myHandlerThread.getLooper() )
對(duì)應(yīng)源碼為:
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;
}
myHandlerThread.getLooper()返回的就是我們?cè)趓un方法中創(chuàng)建的mLooper。
如果你夠細(xì)心你會(huì)發(fā)現(xiàn),run方法里面當(dāng)mLooper創(chuàng)建完成后有個(gè)notifyAll(),getLooper()中有個(gè)wait(),這是為什么呢?因?yàn)榈膍Looper在一個(gè)線(xiàn)程中執(zhí)行,而我們的handler是在UI線(xiàn)程初始化的,也就是說(shuō),我們必須等到mLooper創(chuàng)建完成,才能正確的返回getLooper()。wait(),notify()就是為了解決這兩個(gè)線(xiàn)程的同步問(wèn)題。