實(shí)例分析Android中HandlerThread線程用法
一、HandlerThread的介紹及使用舉例
HandlerThread是什么鬼?其本質(zhì)就是一個(gè)線程,但是HandlerThread在啟動(dòng)的時(shí)候會(huì)幫我們準(zhǔn)備好一個(gè)Looper,并供外界使用,說白了就是使我們在子線程中更方便的使用Handler,比如沒有HandlerThread我們要在子線程使用Handler,寫法如下:
private Handler mHandler;
@Override
public void run() {
super.run();
Looper.prepare();
mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
}
};
Looper.loop();
}
有了HandlerThread就不用我們自己管理Looper了,至于為什么分析源碼的時(shí)候就明白了。
HandlerThread使用簡單介紹:
首先我們要初始化HandlerThread然后調(diào)用其start方法,也就是開啟線程:
mHandlerThread = new HandlerThread("mHandlerThread");//這里的mHandlerThread其實(shí)就是線程的名字 mHandlerThread.start();
接下來初始化一個(gè)Handler并且將mHandlerThread中的Looper作為構(gòu)造函數(shù)參數(shù)傳遞給Handler:
mHandler = new Handler(mHandlerThread.getLooper())
這樣就保證了Hnadler運(yùn)行在子線程。并且需要在適合的時(shí)機(jī)調(diào)用HandlerThread的quit方法或quitSafely方法,如Activity銷毀的時(shí)候:
@Override protected void onDestroy() { // super.onDestroy(); //釋放資源 mHandlerThread.quit(); }
quit()與quitSafely()方法比較(這里只說一些結(jié)論,源碼可以自己查看):
相同點(diǎn):
調(diào)用之后MessageQueue消息隊(duì)列均不在接受新的消息加入隊(duì)列。
不同點(diǎn):
quit方法把MessageQueue消息池中所有的消息全部清空。quitSafely方法只會(huì)清空MessageQueue消息池中所有的延遲消息(延遲消息是指通過sendMessageDelayed或postDelayed等方法發(fā)送的消息),非延遲消息則不清除繼續(xù)派發(fā)出去讓Handler去處理。
接下來我們完整看一下HandlerThread例子源碼:
public class MainActivity extends Activity {
private HandlerThread mHandlerThread;
private Handler mHandler;
private boolean flag;
//
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandlerThread = new HandlerThread("mHandlerThread");
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
//
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(flag){
Log.i("HandlerThread", "更新:"+new Random().nextInt(1000));
}
mHandler.sendEmptyMessage(1);
}
};
}
@Override
protected void onResume() {
//
super.onResume();
flag = true;
mHandler.sendEmptyMessage(1);
}
@Override
protected void onPause() {
//
super.onPause();
flag = false;
}
@Override
protected void onDestroy() {
//
super.onDestroy();
//釋放資源
mHandlerThread.quit();
}
}
運(yùn)行程序就會(huì)在控制臺(tái)看到每隔兩秒有Log打出。至于HandlerThrea的使用就到此為止了,看懂上面小例子就差不多了。
二、HandlerThread的源碼分析
HandlerThread源碼非常簡短,出去注釋不到100行,這里就直接全部貼出來了:
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
/**
* 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;
}
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
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;
}
/**
* 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()) {
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;
}
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;
}
/**
* Returns the identifier of this thread. See Process.myTid().
*/
public int getThreadId() {
return mTid;
}
}
看第一行就知道了其本質(zhì)就是一個(gè)線程。
6-9行以及17-20行構(gòu)造函數(shù),也很簡單,就是初始化的時(shí)候我們可以定義線程名字,還可以傳入線程優(yōu)先級(jí)。
初始化完成,緊接著調(diào)用start()開發(fā)線程就會(huì)執(zhí)行run方法邏輯。
30-41行代碼,最重要的就是調(diào)用Looper.prepare()以及Looper.loop()方法為我們在子線程準(zhǔn)備好一個(gè)Looper。并且用變量mLooper記錄,調(diào)用getLooper()方法的時(shí)候返回。
但是,細(xì)心的你肯定發(fā)現(xiàn)run()方法中有個(gè)notifyAll(),getLooper()中有個(gè)wait()為什么要加這些鳥玩意?
大家發(fā)現(xiàn)沒在HandlerThread 例子中Handler的創(chuàng)建是在主線程完成的,創(chuàng)建的時(shí)候需要調(diào)用HandlerThread的getLooper()獲取mLooper作為參數(shù)傳遞給Handler的構(gòu)造函數(shù),而Looper的創(chuàng)建是在子線程中創(chuàng)建的,這里就有線程同步問題了,比如我們調(diào)用getLooper()的時(shí)候HandlerThread中run()方法還沒執(zhí)行完,mLooper變量還未賦值,此時(shí)就執(zhí)行了wait()等待邏輯,一直等到run()方法中mLooper被賦值,之后立即執(zhí)行notifyAll(),然后getLooper()就可以正確返回mLooper了。
明白了吧,不明的話這里需要花些時(shí)間好好理解下,好了源碼主要部分就分析完了,看到這里相信你對HandlerThread有了一定的了解了。
HandlerThread 還是比較簡單理解的,好了,本篇到此為止,希望對你有幫助。
相關(guān)文章
解析離線安裝Eclipse的Android ADT開發(fā)插件的具體操作(圖文)
本篇文章是對離線安裝Eclipse的Android ADT開發(fā)插件的具體操作進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05解決VSCode調(diào)試react-native android項(xiàng)目錯(cuò)誤問題
這篇文章主要介紹了VSCode調(diào)試react-native android項(xiàng)目錯(cuò)誤解決辦法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12Android網(wǎng)頁H5 Input選擇相機(jī)和系統(tǒng)相冊
這篇文章主要為大家詳細(xì)介紹了Android網(wǎng)頁H5 Input選擇相機(jī)和系統(tǒng)相冊,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-10-10Android如何實(shí)現(xiàn)翻轉(zhuǎn)動(dòng)畫效果(卡片翻轉(zhuǎn))
卡片翻轉(zhuǎn)這個(gè)效果大家應(yīng)該都不陌生,這篇文章主要給大家介紹了關(guān)于Android如何實(shí)現(xiàn)翻轉(zhuǎn)動(dòng)畫效果的相關(guān)資料,文中將實(shí)現(xiàn)的源代碼以及過程中遇到的bug都介紹的非常詳細(xì),需要的朋友可以參考下2021-08-08android Textview文字監(jiān)控(Textview使用方法)
以手機(jī)號(hào)充值為例,當(dāng)用戶輸入最后一位數(shù)時(shí)候,進(jìn)行匯率的變換,本文就實(shí)現(xiàn)類似這樣的功能2013-11-11Android快速實(shí)現(xiàn)發(fā)送郵件實(shí)例
本篇文章主要介紹了Android快速實(shí)現(xiàn)發(fā)送郵件實(shí)例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-04-04Android Studio實(shí)現(xiàn)簡單的通訊錄
這篇文章主要為大家詳細(xì)介紹了Android Studio實(shí)現(xiàn)簡單的通訊錄,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-04-04Android高級(jí)組件ImageSwitcher圖像切換器使用方法詳解
這篇文章主要為大家詳細(xì)介紹了Android高級(jí)組件ImageSwitcher圖像切換器的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12