HandlerThread 是一種內建了訊息傳遞機制的 Thread,很適合用來當作循序任務處理器。其實也是內建了 Looper 與 MessageQueue,等待要處理的訊息。
HandlerThread handlerThread = new HandlerThread("HandlerThread");
handlerThread.start();
mHandler = new Handler(handlerThread.getLooper()) {
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
Handler 的存取能夠透過 HandlerThread 的子類別,設定為私有的,並確保 Looper 不可被存取,由該子類別提供給客戶端公用的存取 method。
public class MyHandlerThread extends HandlerThread {
private Handler mHandler;
public MyHandlerThread() {
super("MyHandlerThread", Process.THREAD_PRIORITY_BACKGROUND);
}
@Override
protected void onLooperPrepared() {
super.onLooperPrepared();
mHandler = new Handler(getLooper()) {
@Override
public void handleMessage(Message msg) {
switch(msg.what) {
case 1:
// Handle message
break;
case 2:
// Handle message
break;
}
}
};
}
public void publishedMethod1() {
mHandler.sendEmptyMessage(1);
}
public void publishedMethod2() {
mHandler.sendEmptyMessage(2);
}
}
生命週期
Creation
預設 priority 為 Process.THREADPRIORITYDEFAULT ,跟 UI Thread 一樣,可以設定為 Process.THREADPRIORITYBACKGROUND,來執行非關鍵性任務。
HandlerThread(String name); HandlerThread(String name, int priority);
Execution
HandlerThread 永遠會準備好接收訊息。
Reset
Message Queue 可被重設,不處理裡面的訊息,但該 thread 會繼續存活,可以處理新的訊息。重設時不會影響已經在處理中的,以及已經被派送的訊息。
public void resetHandlerThread() { mHandler.removeCallbacksAndMessages(null); }
Termination
HandlerThread 透過 quit 及 quitSafely 被終止,使用 quitSafely 可以將已經派送的訊息處理完成後,才結束 HandlerThread。
public void stopHandlerThread(HandlerThread handlerThread) { handlerThread.quit(); handlerThread.quitSafely(); }
也可以利用 finalization task 來結束。
handler.post(new Runnable() { @Override public void run() { Looper.myLooper().quit(); } });
使用案例1: SharedPreferences
public class SharedPreferencesActivity extends Activity {
TextView mTextValue;
/**
* Show read value in a TextView.
* UI 執行緒的 Handler
*/
private Handler mUiHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 0) {
Integer i = (Integer)msg.obj;
mTextValue.setText(Integer.toString(i));
}
}
};
// 讀寫 SharedPreference 的 background thread
private class SharedPreferenceThread extends HandlerThread {
private static final String KEY = "key";
private SharedPreferences mPrefs;
private static final int READ = 1;
private static final int WRITE = 2;
private Handler mHandler;
public SharedPreferenceThread() {
super("SharedPreferenceThread", Process.THREAD_PRIORITY_BACKGROUND);
mPrefs = getSharedPreferences("LocalPrefs", MODE_PRIVATE);
}
@Override
protected void onLooperPrepared() {
super.onLooperPrepared();
mHandler = new Handler(getLooper()) {
@Override
public void handleMessage(Message msg) {
switch(msg.what) {
case READ:
mUiHandler.sendMessage(mUiHandler.obtainMessage(0, mPrefs.getInt(KEY, 0)));
break;
case WRITE:
SharedPreferences.Editor editor = mPrefs.edit();
editor.putInt(KEY, (Integer)msg.obj);
editor.commit();
break;
}
}
};
}
public void read() {
mHandler.sendEmptyMessage(READ);
}
public void write(int i) {
mHandler.sendMessage(Message.obtain(Message.obtain(mHandler, WRITE, i)));
}
}
private int mCount;
private SharedPreferenceThread mThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_shared_preferences);
mTextValue = (TextView) findViewById(R.id.text_value);
mThread = new SharedPreferenceThread();
// 建立 Activity 時,啟動 SharedPreferenceThread
mThread.start();
}
/**
* Write dummy value from the UI thread.
*/
public void onButtonClickWrite(View v) {
mThread.write(mCount++);
}
/**
* Initiate a read from the UI thread.
*/
public void onButtonClickRead(View v) {
mThread.read();
}
/**
* Ensure that the background thread is terminated with the Activity.
*/
@Override
protected void onDestroy() {
super.onDestroy();
mThread.quit();
}
}
使用案例2: 鏈結的網路呼叫
當第一個網路資源時,就繼續處理第二個,如果失敗,就停止這個 background thread。
public class ChainedNetworkActivity extends Activity {
private static final int DIALOG_LOADING = 0;
private static final int SHOW_LOADING = 1;
private static final int DISMISS_LOADING = 2;
// 在 UI thread 上處理 dialog
Handler dialogHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case SHOW_LOADING:
showDialog(DIALOG_LOADING);
break;
case DISMISS_LOADING:
dismissDialog(DIALOG_LOADING);
}
}
};
private class NetworkHandlerThread extends HandlerThread {
private static final int STATE_A = 1;
private static final int STATE_B = 2;
private Handler mHandler;
public NetworkHandlerThread() {
super("NetworkHandlerThread", Process.THREAD_PRIORITY_BACKGROUND);
}
@Override
protected void onLooperPrepared() {
super.onLooperPrepared();
mHandler = new Handler(getLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case STATE_A:
// 第一個任務的處理結果
dialogHandler.sendEmptyMessage(SHOW_LOADING);
String result = networkOperation1();
if (result != null) {
sendMessage(obtainMessage(STATE_B, result));
} else {
// 失敗時,就終止dialogHandler.sendEmptyMessage(DISMISS_LOADING);
}
break;
case STATE_B:
networkOperation2((String) msg.obj);
dialogHandler.sendEmptyMessage(DISMISS_LOADING);
break;
}
}
};
// 開始第一個任務
fetchDataFromNetwork();
}
private String networkOperation1() {
SystemClock.sleep(2000); // Dummy
return "A string";
}
private void networkOperation2(String data) {
// Pass data to network, e.g. with HttpPost.
SystemClock.sleep(2000); // Dummy
}
/**
* Publicly exposed network operation
*/
public void fetchDataFromNetwork() {
mHandler.sendEmptyMessage(STATE_A);
}
}
private NetworkHandlerThread mThread;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mThread = new NetworkHandlerThread();
mThread.start();
}
@Override
protected Dialog onCreateDialog(int id) {
Dialog dialog = null;
switch (id) {
case DIALOG_LOADING:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Loading...");
dialog = builder.create();
break;
}
return dialog;
}
/**
* Ensure that the background thread is terminated with the Activity.
*/
@Override
protected void onDestroy() {
super.onDestroy();
mThread.quit();
}
}
沒有留言:
張貼留言