在上篇 Android Looper + Handler + Message + MessageQueue(Worker Thread)介紹 Worker Thread (Android訊息傳送機制)
本篇會持續示範訊息傳送機制的其他進階用法,
1.傳送訊息夾帶參數
這是基本建立訊息並使用Handler傳送訊息的用法
private void sendMessageToWorkerHandler()
{
Handler handler = mCustomizeWorkerThread.getHandler();
if (handler != null) {
Message message = handler.obtainMessage(2);
handler.sendMessage(message);
}
}
傳送訊息可以夾帶參數,讓Handler在處理訊息(handleMessage方法)時,可根據參數作更多處理 e.g.,
夾帶簡單整數型態arg1和arg2
private void sendMessageWithArgsToWorkerHandler()
{
Handler handler = mCustomizeWorkerThread.getHandler();
if (handler != null) {
Message message = Message.obtain();
message.what = 3;
message.arg1 = 10;
message.arg2 = 100;
handler.sendMessage(message);
}
}
另外還可以夾帶自定義類別的物件,以下為自定義類別,為了簡單示範,只持有一個String和一個Int類別成員
package com.foxx.threads;
public class CustomizeMessageObject
{
private String mName = "";
private int mType;
public CustomizeMessageObject(String name, int type){
mName = name;
mType = type;
}
public String getName()
{
return mName;
}
public void setName(String name)
{
mName = name;
}
public int getType()
{
return mType;
}
public void setType(int type)
{
mType = type;
}
}
夾帶自定義物件的方式
private void sendMessageWithObjectToWorkerHandler()
{
Handler handler = mCustomizeWorkerThread.getHandler();
if (handler != null) {
Message message = Message.obtain();
message.what = 4;
message.obj = new CustomizeMessageObject("Foxx", 123);
handler.sendMessage(message);
}
}
修改在Activity發送訊息的部份,點擊按鈕會依序發送3個訊息
@Override
public void onClick(View view)
{
int uiId = view.getId();
switch (uiId) {
case R.id.startThread:
sendMessageToWorkerHandler();
sendMessageWithArgsToWorkerHandler();
sendMessageWithObjectToWorkerHandler();
break;
}
}
修改CustomizeWorkerHandler處理訊息的部份,針對message.what的數值作判斷
public void handleMessage(Message message)
{
switch (message.what) {
case 2:
String result = HttpPageData.getPageData("https://www.google.com.tw/");
setResultToMainActivity(result);
break;
case 3:
Log.d(TAG, "message.arg1:" + message.arg1);
Log.d(TAG, "message.arg2:" + message.arg2);
break;
case 4:
CustomizeMessageObject messageObject = (CustomizeMessageObject) message.obj;
Log.d(TAG, "MessageObject.name:" + messageObject.getName());
Log.d(TAG, "MessageObject.type:" + messageObject.getType());
break;
}
}
以下是Logcat的輸出
06-12 11:34:01.463: D/WorkerHandler(16289): message.arg1:10 06-12 11:34:01.463: D/WorkerHandler(16289): message.arg2:100 06-12 11:34:01.463: D/WorkerHandler(16289): MessageObject.name:Foxx 06-12 11:34:01.463: D/WorkerHandler(16289): MessageObject.type:123
2.提醒使用者訊息處理
假設處理訊息時並沒有提醒使用者,會讓使用者誤判點擊按鍵卻沒有反應造成使用者多次點擊,為了避免這種情況,最好在送出訊息時出現提示。
提示可由Dialog或是ProgressDialog組成。
首先在MainActivity加入並建立提示元件,提供外部存取的方法
public class MainActivity extends ActionBarActivity implements OnClickListener
{
...
private AlertDialog mProcessingMessageDialog;
private void initUIComponents()
{
initProcessingMessageDialog();
...
}
private void initProcessingMessageDialog()
{
mProcessingMessageDialog = new AlertDialog.Builder(this).create();
mProcessingMessageDialog.setTitle("Processing...");
mProcessingMessageDialog.setCanceledOnTouchOutside(false);
}
public AlertDialog getProcessingMessageDialog(){
return mProcessingMessageDialog;
}
接著在CustomizeWorkerHandler加入操作和呼叫點
第5行當該Handler收到從Looper傳送過來的訊息,立即顯示ProcessingMessageDialog
第21行當該Handler處理完Message,關閉ProcessingMessageDialog
class CustomizeWorkerHandler extends Handler
{
public void handleMessage(Message message)
{
showProcessingDialog();
switch (message.what) {
case 2:
String result = HttpPageData.getPageData("https://www.google.com.tw/");
setResultToMainActivity(result);
break;
case 3:
Log.d(TAG, "message.arg1:" + message.arg1);
Log.d(TAG, "message.arg2:" + message.arg2);
break;
case 4:
CustomizeMessageObject messageObject = (CustomizeMessageObject) message.obj;
Log.d(TAG, "MessageObject.name:" + messageObject.getName());
Log.d(TAG, "MessageObject.type:" + messageObject.getType());
break;
}
closeProcessingDialog();
}
private void showProcessingDialog()
{
mMainActivity.runOnUiThread(new Runnable() {
@Override
public void run()
{
mMainActivity.getProcessingMessageDialog().show();
}
});
}
private void closeProcessingDialog()
{
mMainActivity.runOnUiThread(new Runnable() {
@Override
public void run()
{
mMainActivity.getProcessingMessageDialog().dismiss();
}
});
}
}
3.雙重Handler溝通
CustomizeWorkerHandler 的 showProcessingDialog 和 closeProcessingDialog方法其實是為了調用UI Thread的UI元件。
如果把處理UI Thread的內容集中寫在CustomizeWorkerHandler,會調用多次的 mMainActivity.runOnUiThread方法,
導致CustomizeWorkerHandler類別的冗長,其實可以在UI Thread中建立另一個UI Handler,當CustomizeWorkerHandler有結果產生時
藉由UI Handler發送訊息到UI Thread,訊息包含處理完的結果,把結果的處理轉回到 UI Thread中。
先新增UIHandler類別並建立實體,提供存取方法,把結果的處理放在handleMessage方法中,順便修正Magic Number
public class MainActivity extends ActionBarActivity implements OnClickListener
{
...
public static final int GET_PAGE_DATA = 0;
public static final int SEND_MESSAGE_ARGS = 1;
public static final int SEND_MESSAGE_OBJECT = 2;
private UIHandler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState)
{
...
initUIHandler();
...
}
private void initUIHandler()
{
mHandler = new UIHandler();
}
public UIHandler getHandler()
{
return mHandler;
}
class UIHandler extends Handler
{
@Override
public void handleMessage(Message msg)
{
switch (msg.what) {
case GET_PAGE_DATA:
String result = (String) msg.obj;
mResultTextView.setText(result);
break;
case SEND_MESSAGE_ARGS:
mResultTextView.setText(""+msg.arg1+msg.arg2);
break;
case SEND_MESSAGE_OBJECT:
CustomizeMessageObject messageObject = (CustomizeMessageObject) msg.obj;
mResultTextView.setText(""+messageObject.getName()+messageObject.getType());
break;
}
mProcessingMessageDialog.dismiss();
}
}
修改CustomizeWorkerHandler在handlMessage方法取得UI Handler,並使用UI Handler發送包含結果的訊息,
class CustomizeWorkerHandler extends Handler
{
...
@Override
public void handleMessage(Message message)
{
Message messageToUIHandler = mMainActivity.getHandler().obtainMessage(message.what);
switch (message.what) {
case MainActivity.GET_PAGE_DATA:
messageToUIHandler.obj = HttpPageData.getPageData("https://www.google.com.tw/");
break;
case MainActivity.SEND_MESSAGE_ARGS:
messageToUIHandler.arg1 = message.arg1;
messageToUIHandler.arg2 = message.arg2;
break;
case MainActivity.SEND_MESSAGE_OBJECT:
CustomizeMessageObject messageObject = (CustomizeMessageObject) message.obj;
messageToUIHandler.obj = messageObject;
break;
}
mMainActivity.getHandler().sendMessage(messageToUIHandler);
}
}
如此就能在UI Thread中處理結果。
在〈Android Worker Thread Advanced〉中有 1 則留言
寫得很棒,一看就懂了