原文鏈接
---
# HandlerThread 簡介:
我們知道Thread線程是一次性消費品,當Thread線程執行完一個耗時的任務之后,線程就會被自動銷毀了。如果此時我又有一
個耗時任務需要執行,我們不得不重新創建線程去執行該耗時任務。然而,這樣就存在一個性能問題:多次創建和銷毀線程是很耗
系統資源的。為了解這種問題,我們可以自己構建一個循環線程Looper Thread,當有耗時任務投放到該循環線程中時,線程執行耗
時任務,執行完之后循環線程處于等待狀態,直到下一個新的耗時任務被投放進來。這樣一來就避免了多次創建Thread線程導致的
性能問題了。也許你可以自己去構建一個循環線程,但我可以告訴你一個好消息,Aandroid SDK中其實已經有一個循環線程的框架
了。此時你只需要掌握其怎么使用的就ok啦!當然就是我們今天的主角HandlerThread啦!接下來請HandlerThread上場,鼓掌~~
HandlerThread的父類是Thread,因此HandlerThread其實是一個線程,只不過其內部幫你實現了一個Looper的循環而已。那么我們
先來了解一下Handler是怎么使用的吧!
【轉載請注明出處:[Android HandlerThread 源碼分析](http://blog.csdn.net/feiduclear_up/article/details/46840523)?CSDN 廢墟的樹】
# HandlerThread使用步驟:
## 1.創建實例對象
~~~
HandlerThread handlerThread = new HandlerThread("handlerThread");
~~~
以上參數可以任意字符串,參數的作用主要是標記當前線程的名字。
## 2.啟動HandlerThread線程
~~~
handlerThread.start();
~~~
到此,我們就構建完一個循環線程了。那么你可能會懷疑,那我怎么將一個耗時的異步任務投放到HandlerThread線程中去執行呢?當然是有辦法的,接下來看第三部。
## 3.構建循環消息處理機制
~~~
Handler subHandler = new Handler(handlerThread.getLooper(), new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
//實現自己的消息處理
return true;
}
});
~~~
第三步創建一個Handler對象,將上面HandlerThread中的looper對象最為Handler的參數,然后重寫Handler的Callback接口類中的
handlerMessage方法來處理耗時任務。
**總結:**以上三步順序不能亂,必須嚴格按照步驟來。到此,我們就可以調用subHandler以發送消息的形式發送耗時任務到線程
HandlerThread中去執行。言外之意就是subHandler中Callback接口類中的handlerMessage方法其實是在工作線程中執行的。
# HandlerThread實例:
~~~
package com.example.handlerthread;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
private Handler mSubHandler;
private TextView textView;
private Button button;
private Handler.Callback mSubCallback = new Handler.Callback() {
//該接口的實現就是處理異步耗時任務的,因此該方法執行在子線程中
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case 0:
Message msg1 = new Message();
msg1.what = 0;
msg1.obj = java.lang.System.currentTimeMillis();
mUIHandler.sendMessage(msg1);
break;
default:
break;
}
return false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView);
button = (Button) findViewById(R.id.button);
HandlerThread workHandle = new HandlerThread("workHandleThread");
workHandle.start();
mSubHandler = new Handler(workHandle.getLooper(), mSubCallback);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//投放異步耗時任務到HandlerThread中
mSubHandler.sendEmptyMessage(0);
}
});
}
}
~~~
# HandlerThread源碼分析
## HandlerThread構造方法
~~~
/**
* 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;
//當前線程id
int mTid = -1;
//當前線程持有的Looper對象
Looper mLooper;
//構造方法
public HandlerThread(String name) {
//調用父類默認的方法創建線程
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
//帶優先級參數的構造方法
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
...............
}
~~~
分析:該類開頭就給出了一個描述:該類用于創建一個帶Looper循環的線程,Looper對象用于創建Handler對象,值得注意的是在創建Handler
對象之前需要調用start()方法啟動線程。這里可能有些人會有疑問?為啥需要先調用start()方法之后才能創建Handler呢?后面我們會解答。
上面的代碼注釋已經很清楚了,HandlerThread類有兩個構造方法,不同之處就是設置當前線程的優先級參數。你可以根據自己的情況來設置優先
級,也可以使用默認優先級。
## HandlerThrad的run方法
~~~
public class HandlerThread extends Thread {
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}
@Override
public void run() {
//獲得當前線程的id
mTid = Process.myTid();
//準備循環條件
Looper.prepare();
//持有鎖機制來獲得當前線程的Looper對象
synchronized (this) {
mLooper = Looper.myLooper();
//發出通知,當前線程已經創建mLooper對象成功,這里主要是通知getLooper方法中的wait
notifyAll();
}
//設置當前線程的優先級
Process.setThreadPriority(mPriority);
//該方法實現體是空的,子類可以實現該方法,作用就是在線程循環之前做一些準備工作,當然子類也可以不實現。
onLooperPrepared();
//啟動loop
Looper.loop();
mTid = -1;
}
}
~~~
分析:以上代碼中的注釋已經寫得很清楚了,以上run方法主要作用就是調用了Looper.prepare和Looper.loop構建了一個循環線程。值得一提的
是,run方法中在啟動loop循環之前調用了onLooperPrepared方法,該方法的實現是一個空的,用戶可以在子類中實現該方法。該方法的作用是
在線程loop之前做一些初始化工作,當然你也可以不實現該方法,具體看需求。由此也可以看出,Google工程師在編寫代碼時也考慮到代碼的可擴展性。牛B!
# HandlerThread的其他方法
## getLooper獲得當前線程的Looper對象
~~~
/**
* 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() {
//如果線程不是存活的,則直接返回null
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
//如果線程已經啟動,但是Looper還未創建的話,就等待,知道Looper創建成功
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
~~~
分析:其實方法開頭的英文注釋已經解釋的很清楚了:該方法主要作用是獲得當前HandlerThread線程中的mLooper對象。
首先判斷當前線程是否存活,如果不是存活的,這直接返回null。其次如果當前線程存活的,在判斷線程的成員變量mLooper是否為null,如果為
null,說明當前線程已經創建成功,但是還沒來得及創建Looper對象,因此,這里會調用wait方法去等待,當run方法中的notifyAll方法調用之后
通知當前線程的wait方法等待結束,跳出循環,獲得mLooper對象的值。
**總結:**在獲得mLooper對象的時候存在一個同步的問題,只有當線程創建成功并且Looper對象也創建成功之后才能獲得mLooper的值。這里等待方法wait和run方法中的notifyAll方法共同完成同步問題。
## quit結束當前線程的循環
~~~
/**
* Quits the handler thread's looper.
* <p>
* Causes the handler thread's looper to terminate without processing any
* more messages in the message queue.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p class="note">
* Using this method may be unsafe because some messages may not be delivered
* before the looper terminates. Consider using {@link #quitSafely} instead to ensure
* that all pending work is completed in an orderly manner.
* </p>
*
* @return True if the looper looper has been asked to quit or false if the
* thread had not yet started running.
*
* @see #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;
}
~~~
分析:以上有兩種讓當前線程退出循環的方法,一種是安全的,一中是不安全的。至于兩者有什么區別? quitSafely方法效率比quit方法標率低一點,但是安全。具體選擇哪種就要看具體項目了。
# 總結:
1.HandlerThread適用于構建循環線程。
2.在創建Handler作為HandlerThread線程消息執行者的時候必須調用start方法之后,因為創建Handler需要的Looper參數是從HandlerThread類中獲得,而Looper對象的賦值又是在HandlerThread的run方法中創建。
3.關于HandlerThread和Service的結合使用請參考另一篇博客:[Android IntentService 源碼分析](http://blog.csdn.net/feiduclear_up/article/details/46964457)
- 0-發現
- AndroidInterview-Q-A
- Android能讓你少走彎路的干貨整理
- LearningNotes
- temp
- temp11
- 部分地址
- 0-待辦任務
- 待補充列表
- 0-未分類
- AndroidView事件分發與滑動沖突處理
- Spannable
- 事件分發機制詳解
- 1-Java
- 1-Java-01基礎
- 未歸檔
- 你應該知道的JDK知識
- 集合框架
- 1-Java-04合集
- Java之旅0
- Java之旅
- JAVA之旅01
- JAVA之旅02
- JAVA之旅03
- JAVA之旅04
- JAVA之旅05
- JAVA之旅06
- JAVA之旅07
- JAVA之旅08
- JAVA之旅09
- java之旅1
- JAVA之旅10
- JAVA之旅11
- JAVA之旅12
- JAVA之旅13
- JAVA之旅14
- JAVA之旅15
- JAVA之旅16
- JAVA之旅17
- JAVA之旅18
- JAVA之旅19
- java之旅2
- JAVA之旅20
- JAVA之旅21
- JAVA之旅22
- JAVA之旅23
- JAVA之旅24
- JAVA之旅25
- JAVA之旅26
- JAVA之旅27
- JAVA之旅28
- JAVA之旅29
- java之旅3
- JAVA之旅30
- JAVA之旅31
- JAVA之旅32
- JAVA之旅33
- JAVA之旅34
- JAVA之旅35
- 1-Java-05辨析
- HashMapArrayMap
- Java8新特性
- Java8接口默認方法
- 圖解HashMap(1)
- 圖解HashMap(2)
- 2-Android
- 2-Android-1-基礎
- View繪制流程
- 事件分發
- AndroidView的事件分發機制和滑動沖突解決
- 自定義View基礎
- 1-安卓自定義View基礎-坐標系
- 2-安卓自定義View基礎-角度弧度
- 3-安卓自定義View基礎-顏色
- 自定義View進階
- 1-安卓自定義View進階-分類和流程
- 10-安卓自定義View進階-Matrix詳解
- 11-安卓自定義View進階-MatrixCamera
- 12-安卓自定義View進階-事件分發機制原理
- 13-安卓自定義View進階-事件分發機制詳解
- 14-安卓自定義View進階-MotionEvent詳解
- 15-安卓自定義View進階-特殊形狀控件事件處理方案
- 16-安卓自定義View進階-多點觸控詳解
- 17-安卓自定義View進階-手勢檢測GestureDetector
- 2-安卓自定義View進階-繪制基本圖形
- 3-安卓自定義View進階-畫布操作
- 4-安卓自定義View進階-圖片文字
- 5-安卓自定義View進階-Path基本操作
- 6-安卓自定義View進階-貝塞爾曲線
- 7-安卓自定義View進階-Path完結篇偽
- 8-安卓自定義View進階-Path玩出花樣PathMeasure
- 9-安卓自定義View進階-Matrix原理
- 通用類介紹
- Application
- 2-Android-2-使用
- 2-Android-02控件
- ViewGroup
- ConstraintLayout
- CoordinatorLayout
- 2-Android-03三方使用
- Dagger2
- Dagger2圖文完全教程
- Dagger2最清晰的使用教程
- Dagger2讓你愛不釋手-終結篇
- Dagger2讓你愛不釋手-重點概念講解、融合篇
- dagger2讓你愛不釋手:基礎依賴注入框架篇
- 閱讀筆記
- Glide
- Google推薦的圖片加載庫Glide:最新版使用指南(含新特性)
- rxjava
- 這可能是最好的RxJava2.x入門教程完結版
- 這可能是最好的RxJava2.x入門教程(一)
- 這可能是最好的RxJava2.x入門教程(三)
- 這可能是最好的RxJava2.x入門教程(二)
- 這可能是最好的RxJava2.x入門教程(五)
- 這可能是最好的RxJava2.x入門教程(四)
- 2-Android-3-優化
- 優化概況
- 各種優化
- Android端秒開優化
- apk大小優化
- 內存分析
- 混淆
- 2-Android-4-工具
- adb命令
- 一鍵分析Android的BugReport
- 版本控制
- git
- git章節簡述
- 2-Android-5-源碼
- HandlerThread 源碼分析
- IntentService的使用和源碼分析
- 2-Android-9-辨析
- LRU算法
- 什么是Bitmap
- 常見圖片壓縮方式
- 3-Kotlin
- Kotlin使用筆記1-草稿
- Kotlin使用筆記2
- kotlin特性草稿
- Kotlin草稿-Delegation
- Kotlin草稿-Field
- Kotlin草稿-object
- 4-JavaScript
- 5-Python
- 6-Other
- Git
- Gradle
- Android中ProGuard配置和總結
- gradle使用筆記
- Nexus私服搭建
- 編譯提速最佳實踐
- 7-設計模式與架構
- 組件化
- 組件化探索(OKR)
- 1-參考列表
- 2-1-組件化概述
- 2-2-gradle配置
- 2-3-代碼編寫
- 2-4-常見問題
- 2-9-值得一讀
- 8-數據結構與算法
- 0臨時文件
- 漢諾塔
- 8-數據-1數據結構
- HashMap
- HashMap、Hashtable、HashSet 和 ConcurrentHashMap 的比較
- 遲到一年HashMap解讀
- 8-數據-2算法
- 1個就夠了
- Java常用排序算法(必須掌握的8大排序算法)
- 常用排序算法總結(性能+代碼)
- 必須知道的八大種排序算法(java實現)
- 9-職業
- 閱讀
- 書單
- 面試
- 面試-01-java
- Java面試題全集駱昊(上)
- Java面試題全集駱昊(下)
- Java面試題全集駱昊(中)
- 面試-02-android
- 40道Android面試題
- 面試-03-開源源碼
- Android圖片加載框架最全解析(二),從源碼的角度理解Glide的執行流程
- 面試-07-設計模式
- 面試-08-算法
- 面試-09-其他
- SUMMARY
- 版權說明
- temp111