HanlderThread
繼承自Thread
,它的run()
中通過Looper.prepare()
創建了消息隊列,并通過Looper.loop()
開啟了消息循環,這樣我們就可以在HandlerThread
中創建Handler
了(對Android
消息機制不熟悉的可以參考Android消息機制(Handler、Looper、MessageQueue),從而外界通過Hanlder
通知HandlerThread
來執行一個具體的任務。
1.HanlderThread的使用
下面來簡單的演示一下HandlerThread
的使用,布局文件沒有任何作用所以就不貼出來了
public class MainActivity extends AppCompatActivity {
/**
* 工作消息標志
*/
private final static int MSG_WORK = 0x01;
private Handler mHandler;
private HandlerThread mHandlerThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandlerThread = new HandlerThread("HandlerThread");
mHandlerThread.start(); //開始線程
mHandler = new Handler(mHandlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
try {
Thread.sleep(3000); //模擬延時操作
Log.e(Thread.currentThread().getName(), (int) (Math.random() * 3000 + 1000) + "");
mHandler.sendEmptyMessageDelayed(MSG_WORK, 1000); //延時一秒發送工作消息
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
mHandler.sendEmptyMessage(MSG_WORK); //發送工作消息,觸發消息Handler執行
}
@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeMessages(MSG_WORK); //移除隊列中為執行的工作消息
mHandlerThread.quit(); //退出線程
}
}
下面是logcat
的輸出結果:
07-08 14:08:19.522 1404-1619/com.zhong.handlerthread E/HandlerThread: 1902
07-08 14:08:23.523 1404-1619/com.zhong.handlerthread E/HandlerThread: 3108
07-08 14:08:27.525 1404-1619/com.zhong.handlerthread E/HandlerThread: 3630
07-08 14:08:31.527 1404-1619/com.zhong.handlerthread E/HandlerThread: 1041
07-08 14:08:35.528 1404-1619/com.zhong.handlerthread E/HandlerThread: 2845
07-08 14:08:39.529 1404-1619/com.zhong.handlerthread E/HandlerThread: 3871
07-08 14:08:43.531 1404-1619/com.zhong.handlerthread E/HandlerThread: 1767
07-08 14:08:47.533 1404-1619/com.zhong.handlerthread E/HandlerThread: 2593
每隔4s輸出當前線程的名稱和一個隨機數,通過線程名稱我們可以發現這段代碼確實是在HandlerThread
線程中執行的。上面的程序毫無使用價值,只是為了演示HandlerThread
的使用,HandlerThread
是一個很有用的類,Android
中的IntentService
中就封裝了一個HanderThread
(后續再做介紹,這里就不做解釋了)
注意:
HandlerThread
的run
方法是一個無限循環,Looper.loop()
會不斷循環取消消息交給Handler
處理,沒有消息是會阻塞,所以當不需要使用HandlerThread
時用調用它的quit()
或quitSafely()
終止線程執行。
2.HanlderThread的原理
下面我們通過源碼來分析一下HandlerThread:
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
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() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll(); //喚醒其他線程的等待鎖,這邊是為了喚醒getLooper()方法中的等待鎖
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// 線程開始,該方法會一直等待Looper對象創建完成才會執行,
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
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;
}
}
HandlerThread
源碼實現還是挺清楚的,首先我們看一下它的run()
方法,可以發現該方法中調用Looper.myLooper()
創建了一個Looper
對象mLooper
,并把該對象放到線程變量sThreadLocal
中,然后通過調用Looper.loop()
開啟消息循環,Looper.loop()
方法會不斷循環從MessageQueue
中取出消息處理消息,沒有消息是則會阻塞。getLooper()
方法是獲取線程中的Looper
對象,可以用來初始化Handler
對象。
quit()
和quitSafely()
的區別在于,quit()
會清空所有消息(無論延時或非延時),quitSafely()
只清空延時消息,無論是調用了quit()
方法還是quitSafely()
方法,Looper
就不再接收新的消息。即在調用了Looper
的quit()
或quitSafely()
方法之后,消息循環就終結了,這時候再通過Handler
調用sendMessage
或post
等方法發送消息時均返回false
,線程也就結束了
本人技術有限,歡迎指正,謝謝!