轉載請註明出處:http://blog.csdn.net/vnanyesheshou/article/details/75073307
對於Handler不太懂的可以參考我的這兩篇文章:
Android Handler的基本使用
深入理解Handler、Looper、Messagequeue
這篇主要說一下HandlerThread的使用方法,及分析下其源碼。
1 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.
HandlerThread是Android API提供的一個方便、便捷的類,使用它我們可以快速的創建一個帶有Looper的線程。Looper可以用來創建Handler實例。注意:start()仍然必須被調用。
如下是HandlerThread使用的demo。
package com.zpengyong.hand;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
private final static String TAG = "MainActivity";
private Button mGet;
private TextView mResult;
protected final int MSG_GET = 1;
protected final int MSG_RESULT = 2;
private HandlerThread mHandlerThread;
//子線程中的Handler實例。
private Handler mSubThreadHandler;
//與Ui線程綁定的Handler實例。
private Handler mUiHandler = new Handler(){
public void handleMessage(Message msg) {
Log.i(TAG, "mUiHandler handleMessage thread:"+Thread.currentThread());
switch (msg.what) {
case MSG_RESULT:
mResult.setText((String)msg.obj);
break;
default:
break;
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG, "onCreate thread:"+Thread.currentThread());
mGet = (Button) findViewById(R.id.get);
mGet.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mSubThreadHandler.sendEmptyMessage(MSG_GET);
}
});
mResult = (TextView) findViewById(R.id.result);
initHandlerThraed();
}
private void initHandlerThraed() {
//創建HandlerThread實例
mHandlerThread = new HandlerThread("handler_thread");
//開始運行線程
mHandlerThread.start();
//獲取HandlerThread線程中的Looper實例
Looper loop = mHandlerThread.getLooper();
//創建Handler與該線程綁定。
mSubThreadHandler = new Handler(loop){
public void handleMessage(Message msg) {
Log.i(TAG, "mSubThreadHandler handleMessage thread:"+Thread.currentThread());
switch(msg.what){
case MSG_GET:
try { //模擬延時處理
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
double number = Math.random();
String result = "number:"+number;
//向ui線程發送消息,更新ui。
Message message = new Message();
message.what = MSG_RESULT;
message.obj = result;
mUiHandler.sendMessage(message);
break;
default:
break;
}
};
};
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy");
//退出HandlerThread的Looper循環。
mHandlerThread.quit();
}
}
上述代碼比較簡單,功能也比較簡單,可以在此基礎上進行擴展。
在Actvitiy創建的時候調用initHandlerThraed()函數:
- 創建HandlerThread線程
- 運行線程
- 獲取HandlerThread線程中的Looper實例
- 通過Looper實例創建Handler實例,從而使mSubThreadHandler與該線程連接到一起。
多次點擊按鈕,打印信息如下所示:
07-13 05:15:07.662: I/MainActivity(1472): onCreate thread:Thread[main,5,main]
07-13 05:15:45.382: I/MainActivity(1472): mSubThreadHandler handleMessage thread:Thread[handler_thread,5,main]
07-13 05:15:46.402: I/MainActivity(1472): mUiHandler handleMessage thread:Thread[main,5,main]
07-13 05:15:46.412: I/MainActivity(1472): mSubThreadHandler handleMessage thread:Thread[handler_thread,5,main]
07-13 05:15:47.412: I/MainActivity(1472): mUiHandler handleMessage thread:Thread[main,5,main]
.....
點擊按鈕,向mSubThreadHandler發送消息,mSubThreadHandler中接收到消息進行處理,由打印可知mSubThreadHandler的handleMessage方法運行在子線程中。
模擬耗時操作,生成隨機數,然後向主線程中(mUiHandler)發送消息(Message)。
mUiHandler的handleMessage方法運行在主線程,可以用來更新Ui界面。
Activity銷燬的時候,調用mHandlerThread.quit(),退出HandlerThread的Looper循環。
效果圖如下:
2 HandlerThread源碼分析 |
源碼路徑路徑:frameworks/base/core/java/android/os/HandlerThread.java
先看下HandlerThread的構造方法。
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
//@param name 線程名
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(線程)的子類。創建一個HandlerThread實例,也就是創建了一個特殊的線程實例。
HandlerThread提供了兩個構造方法:
- HandlerThread(String name) 參數爲線程名稱,線程優先級爲Process.THREAD_PRIORITY_DEFAULT。
- HandlerThread(String name, int priority),name爲線程名稱,priority爲設置的線程優先級。
我們知道線程需要通過start()方法來運行線程,HandlerThread也是這樣的。接着看下線程運行的run()方法。
/**
* 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實例
Looper.prepare();
synchronized (this) {
//獲取當前線程的Looper實例
mLooper = Looper.myLooper();
notifyAll();
}
//設置線程優先級
Process.setThreadPriority(mPriority);
onLooperPrepared();
//開始循環
Looper.loop();
mTid = -1;
}
由run方法可知HandlerThrea線程運行創建了Looper實例,並開啓了Looper循環,循環從消息隊列中獲取消息並給Handler進行處理。對於Looper不太明白的可以參考這篇深入理解Handler、Looper、Messagequeue
onLooperPrepared()在Looper循環之前調用,如果需要在Looper循環之前執行一些設置,可以顯式覆蓋此方法。
接着看獲取Looper實例
//獲取HandlerThread線程中的Looper實例
Looper loop = mHandlerThread.getLooper();
對應源碼:
//此方法返回與此線程關聯的Looper。 如果此線程未啓動或由於任何原因isAlive()返回false,此方法將返回null。
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// 如果這個線程已經啓動,將會被阻塞,直到mLooper被初始化爲止。
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
mHandlerThread.getLooper()獲取與該線程綁定的Looper實例。mLooper是在HandlerThread的run()方法中賦值的(也就是在子線程中),getLooper是我們在主線程中調用,該方法會阻塞直到mLooper賦值。
然後demo中通過該looper實例創建Handler
//創建Handler與該線程綁定。
mSubThreadHandler = new Handler(loop)
你可能會好奇爲什麼要這樣長久Handler而不是“new Handler()“這樣呢?因爲我們要創建的Handler要與子線程綁定到一起,要處理子線程中的消息,所以要通過子線程中的looper(有線程對應的消息隊列)實例創建Handler。這樣通過mSubThreadHandler發送的消息會添加到子線程中的消息隊列中,然後Looper實例消息進行分發,交給mSubThreadHandler進行處理。
HandlerThread提供的線程退出方法:
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;
}
quit和quitSafely都是退出HandlerThread的消息循環。其分別調用Looper的quit和quitSafely方法。
quit方法會將消息隊列中的所有消息移除(延遲消息和非延遲消息)。
quitSafely會將消息隊列所有的延遲消息移除,非延遲消息派發出去讓Handler去處理。quitSafely相比於quit方法安全之處在於清空消息之前會派發所有的非延遲消息
HandlerThread適合處理本地IO讀寫操作(數據庫,文件),因爲本地IO操作大多數的耗時屬於毫秒級別,對於單線程 + 異步隊列的形式 不會產生較大的阻塞。而網絡操作相對比較耗時,容易阻塞後面的請求,因此在這個HandlerThread中不適合加入網絡操作。
至此HandlerThread就說完了。有什麼問題歡迎大家指正、交流。