在上篇 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中處理結果。
Jimmy
12 4 月, 2016 9:51 上午寫得很棒,一看就懂了