Android原始碼解析Handler系列第(五)篇 ---HandlerThread你用過嗎?
Handler這個系列總共有5篇,這是最後一篇了。前面三篇部落格,我們從原始碼的層面將Handler訊息機制梳理了一遍,第四篇站在原始碼層之上回顧以前學習時候困惑的一些問題。OK,開始飆車了,學習HandlerThread,如果你還沒有看過我之前的四篇文章,建議去了解,只有深入瞭解的東西,才能被記住。
Android原始碼解析Handler系列第(一)篇 --- Message全域性池
Android原始碼解析Handler系列第(二)篇 --- ThreadLocal詳解
Android原始碼解析Handler系列第(三)篇 --- 深入瞭解Android的訊息機制
Android原始碼解析Handler系列第(四)篇 --- 打破Handler那些困惑事兒
通過前面的學習,我們知道Android整個系統都是通過訊息來驅動的,在主執行緒中預設給我們建立了Looper,即是我們常說的MainLooper,MainLooper是個迴圈器,有合適的訊息立刻取出來交給Handler去處理(一個一個的取出來,一個一個的處理),沒有訊息處於等待狀態。如果有大量的訊息向MainLooper湧來,主執行緒中的MainLooper的工作量會不會很大呢?如果主執行緒壓力過大,介面不流暢咋辦?效能是大個問題!!!為了解這種問題,此刻你會想,我們自己構建一個迴圈執行緒Looper/Thread,當有耗時任務投放到該迴圈執行緒中時,執行緒執行耗時任務,執行完之後迴圈執行緒處於等待狀態,直到下一個新的耗時任務被投放進來,這樣不就分擔了主執行緒的壓力了嘛!!!其實Android SDK中有一個迴圈執行緒的框架---HandlerThread。先來看看怎麼使用HandlerThread。
-
1、建立HandlerThread
mWorkHandler = new HandlerThread("workHandleThread"); mWorkHandler.start();
-
2、獲取獲取HandlerThread的Looper
Looper looper = mWorkHandler.getLooper();
-
3、 建立Handler,通過Looper初始化,mCallback中處理耗時任務
final Handler mSubHandler = new Handler(looper,mCallback);
-
4、投放非同步耗時任務到HandlerThread中
mSubHandler.sendEmptyMessage(0);
- 5、記得回收
@Override protected void onDestroy() { super.onDestroy(); mWorkHandler.quit(); }
完整的程式碼如下:
public class HomeActivity extends AppCompatActivity {
Handler.Callback mCallback=new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
//該介面的實現就是處理非同步耗時任務的,因此該方法執行在子執行緒中
Log.d("Callback", Thread.currentThread().getName());
return false;
}
};
HandlerThread mWorkHandler;
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn= (Button) findViewById(R.id.btn);
Log.d("onCreate", Thread.currentThread().getName());
//1、建立HandlerThread
mWorkHandler = new HandlerThread("workHandlerThread");
mWorkHandler.start();
//2、獲取獲取HandlerThread的Looper
Looper looper = mWorkHandler.getLooper();
//3、 建立Handler,通過Looper初始化
final Handler mSubHandler = new Handler(looper,mCallback);
//4、投放非同步耗時任務到HandlerThread中
// mSubHandler.sendEmptyMessage(0);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mSubHandler.sendEmptyMessage(0);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mWorkHandler != null) {
mWorkHandler.quit();
}
}
}
注意上面Log的輸出
12-08 19:49:25.010 25931-25931/com.zhangwan.www.viewstub D/onCreate: main
12-08 19:49:26.014 25931-30599/com.zhangwan.www.viewstub D/Callback: workHandlerThread
現在確定mCallback的handleMessage是在子執行緒中執行的。所以可以在這裡面去做一些耗時的任務。
OK,基本的用法我們知道了,看看它的原始碼,首先看下它的構造和類定義。
/**
* Handy class for starting a new thread that has a looper. The looper can then be
* used to create handler classes. Note that start() must still be called.
*/
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;
}
//.....程式碼省略
}
HandlerThread的父類是Thread,內部會有一個looper迴圈,並且可以設定優先順序與執行緒的名字。優先順序範圍為-20到19,預設為0,優先順序越高,獲得的CPU資源更多,反之則越少。-20代表優先順序最高,反之19最低。通過建構函式HandlerThread的例項mWorkHandler就被建立起來了。現在呼叫mWorkHandler.start()啟動它。 執行緒的start就是執行HandlerThread的run方法。
@Override
public void run() {
//當前執行緒的id
mTid = Process.myTid();
//準備一個Looper
Looper.prepare();
//持有鎖機制來獲得當前執行緒的Looper物件
synchronized (this) {
//發出通知,當前執行緒已經建立mLooper物件成功,這裡主要是通知getLooper方法中的wait
mLooper = Looper.myLooper();
notifyAll();
}
//設定執行緒的優先順序
Process.setThreadPriority(mPriority);
onLooperPrepared();
//Looper迴圈開啟
Looper.loop();
mTid = -1;
}
用了Looper.prepare和Looper.loop構建了一個迴圈執行緒,onLooperPrepared是一個空實現的方法,子類可以重寫,做一些初始化的工作。
/**
* 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;
}
如果當前執行緒是存活的,在判斷執行緒的成員變數mLooper是否為NULL,如果為NULL,說明當前執行緒已經建立成功,但是還沒有來得及建立Looper物件,所以需要呼叫wait方法等待,當run方法中的notifyAll方法呼叫之後,通知當前執行緒的wait等待結束,跳出迴圈,返回mLooper物件。
當我們要退出時,有quit和quitSafely兩種方式。
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;
}
兩種方式的不同點是,當我們呼叫Looper的quit方法時,實際上執行了MessageQueue中的removeAllMessagesLocked方法,該方法的作用是把MessageQueue訊息池中所有的訊息全部清空,無論是延遲訊息(延遲訊息是指通過sendMessageDelayed或通過postDelayed等方法傳送的需要延遲執行的訊息)還是非延遲訊息。當我們呼叫Looper的quitSafely方法時,實際上執行了MessageQueue中的removeAllFutureMessagesLocked方法,通過名字就可以看出,該方法只會清空MessageQueue訊息池中所有的延遲訊息,並將訊息池中所有的非延遲訊息派發出去讓Handler去處理,quitSafely相比於quit方法安全之處在於清空訊息之前會派發所有的非延遲訊息。需要注意的是Looper的quit方法從API Level 1就存在了,但是Looper的quitSafely方法從API Level 18才新增進來。
最後總結一下使用HandlerThread的好處;
- HandlerThread將loop轉到子執行緒中處理,說白了就是將分擔MainLooper的工作量,降低了主執行緒的壓力,使主介面更流暢。
- HandlerThread擁有自己的訊息佇列,它不會干擾或阻塞UI執行緒。
參考連結:
http://blog.csdn.net/feiduclear_up/article/details/46840523
http://www.cnblogs.com/zhaoyanjun/p/6062880.html
原文連結:http://www.jianshu.com/p/35c8567419fa
著作權歸作者所有,轉載請聯絡作者獲得授權,並標註“簡書作者”。
相關文章
- Android原始碼解析Handler系列第(四)篇 --- 打破Handler那些困惑事兒Android原始碼
- Handler系列原始碼解析原始碼
- Android Handler 原始碼解析Android原始碼
- Android 9.0 原始碼_機制篇 -- 全面解析 HandlerAndroid原始碼
- HandlerThread原始碼解析thread原始碼
- Android 8.1 Handler 原始碼解析Android原始碼
- 知道Handler,那你知道HandlerThread嗎?thread
- Android中HandlerThread的使用及原始碼解析Androidthread原始碼
- HandlerThread和IntentService原始碼解析threadIntent原始碼
- Handler原始碼解析原始碼
- 手把手帶你解析Handler原始碼原始碼
- Handler全家桶之 —— Handler 原始碼解析原始碼
- Android 進階之HandlerThread 使用場景及原始碼解析Androidthread原始碼
- 原始碼深度解析 Handler 機制及應用原始碼
- Android 非同步任務知識梳理(2) HandlerThread 原始碼解析Android非同步thread原始碼
- Android Handler 原始碼探索Android原始碼
- Android——Handler原始碼分析Android原始碼
- Myth原始碼解析系列之五- 服務啟動原始碼解析原始碼
- 【Android原始碼】Handler 機制原始碼分析Android原始碼
- Android原始碼解析(二)動畫篇-- ObjectAnimatorAndroid原始碼動畫Object
- 深入原始碼解析Android中的Handler,Message,MessageQueue,Looper原始碼AndroidOOP
- Backbone系列篇之Backbone.Events原始碼解析原始碼
- Android原始碼學習之handlerAndroid原始碼
- Android開發Handler原始碼分析Android原始碼
- Android多執行緒之Handler、Looper與MessageQueue原始碼解析Android執行緒OOP原始碼
- Framework 原始碼解析知識梳理(4) 從原始碼角度談談 Handler 的應用Framework原始碼
- 原始碼篇:Handler那些事(萬字長文)原始碼
- Spark 原始碼系列(六)Shuffle 的過程解析Spark原始碼
- Android 原始碼分析(二)handler 機制Android原始碼
- Android Handler機制使用,原始碼分析Android原始碼
- Netty原始碼解析4-Handler綜述Netty原始碼
- android apk安裝過程原始碼解析AndroidAPK原始碼
- android View measure過程原始碼解析AndroidView原始碼
- Android進階:五、RxJava2原始碼解析 2AndroidRxJava原始碼
- Android技術棧(五)HashMap和ArrayMap原始碼解析AndroidHashMap原始碼
- dubbo原始碼解析-spi(五)原始碼
- diffusers-原始碼解析-五-原始碼
- Android框架第(五)篇---Retrofit基本使用Android框架