編輯:關於Android編程
今天在做項目處理消息隊列的時候,遇到了這樣一個問題,一個異常。AndroidRuntimeException:This message is already in use。
我當時的具體業務需求情境為,想要跟硬件聯動的時候,保持在一定時間內只有一個操作,如果不idle,就重新發送消息,並且此消息應該delay一段時間,就是TIMEDELAY。
具體出現錯誤的代碼如下:
private class ChargecaseServiceHandler extends Handler {
public ChargecaseServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Command command = new Command();
command.command = msg.what;
if (msg.obj != null) {
command.data = (Bundle) msg.obj;
}
if (sIsLoopBleServiceReady) {
if (isIdle) {
switch (msg.what) {
case MESSAGE_KILL:
stopSelf();
break;
case MESSAGE_START_BLE_SCAN:
startBLEScan();
break;
case MESSAGE_CONNECT:
connect(command.data);
break;
case MESSAGE_DISCONNECT:
attemptDisconnect();
break;
case MESSAGE_RELEASE_DEVICE_ID:
clearData();
break;
case MESSAGE_INITIALIZE:
initialize();
break;
case MESSAGE_RESET_BLE:
resetBleController();
break;
case MESSAGE_STARTUP:
startup();
break;
case MESSAGE_REGISTER:
register(command.data);
break;
case MESSAGE_UNREGISTER:
unregister(command.data);
break;
case MESSAGE_RECONNECT:
reconnect();
break;
case MESSAGE_ADDCARD:
addCard(command.data);
break;
case MESSAGE_GETCARDLIST:
getCardList(command.data);
// removeMessages(MESSAGE_GETCARDLIST);
break;
case MESSAGE_GETCARDDETAIL:
getCardDetail(command.data);
break;
case MESSAGE_REMOVECARD:
removeCard(command.data);
break;
case MESSAGE_CHECK_BATTERY:
checkBattery();
break;
case MESSAGE_SET_DEFAULT_CARD:
setDefaultCard(command.data);
break;
case MESSAGE_ZAP_CARD:
zapCard(command.data);
break;
case MESSAGE_SET_LOCK_TIME:
setLockTimer(command.data);
}
} else {
sServiceHandler.sendMessageDelayed(msg, TIMEDELAY);
}
} else {
Toast.makeText(getApplicationContext(),
"Starting ble for you.", Toast.LENGTH_SHORT).show();
}
}
}然後上網搜了一下,發現實際上說明發送的消息正在消息隊列中,表示現在正在被使用。
參考大神的博客後,(大神博客請移步http://blog.csdn.net/aa4790139/article/details/6579009)
發現解決方法:解決辦法重新創建一個新的消息,發送過去就ok啦!問題解決。
於是我就准備new 一個 message或是obtain 一個message,而不是直接send這個message來進行delay。可是依然出錯,二次出錯的代碼如下:
private class ChargecaseServiceHandler extends Handler {
public ChargecaseServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Command command = new Command();
command.command = msg.what;
if (msg.obj != null) {
command.data = (Bundle) msg.obj;
}
if (sIsLoopBleServiceReady) {
if (isIdle) {
switch (msg.what) {
case MESSAGE_KILL:
stopSelf();
break;
case MESSAGE_START_BLE_SCAN:
startBLEScan();
break;
case MESSAGE_CONNECT:
connect(command.data);
break;
case MESSAGE_DISCONNECT:
attemptDisconnect();
break;
case MESSAGE_RELEASE_DEVICE_ID:
clearData();
break;
case MESSAGE_INITIALIZE:
initialize();
break;
case MESSAGE_RESET_BLE:
resetBleController();
break;
case MESSAGE_STARTUP:
startup();
break;
case MESSAGE_REGISTER:
register(command.data);
break;
case MESSAGE_UNREGISTER:
unregister(command.data);
break;
case MESSAGE_RECONNECT:
reconnect();
break;
case MESSAGE_ADDCARD:
addCard(command.data);
break;
case MESSAGE_GETCARDLIST:
getCardList(command.data);
// removeMessages(MESSAGE_GETCARDLIST);
break;
case MESSAGE_GETCARDDETAIL:
getCardDetail(command.data);
break;
case MESSAGE_REMOVECARD:
removeCard(command.data);
break;
case MESSAGE_CHECK_BATTERY:
checkBattery();
break;
case MESSAGE_SET_DEFAULT_CARD:
setDefaultCard(command.data);
break;
case MESSAGE_ZAP_CARD:
zapCard(command.data);
break;
case MESSAGE_SET_LOCK_TIME:
setLockTimer(command.data);
}
} else {
Message newMsg = sServiceHandler.obtainMessage();
newMsg = msg;
removeMessages(msg.what);
LogHelper.i(LogHelper.CHARGECASE_TAG, newMsg.what + "");
sServiceHandler.sendMessageDelayed(newMsg, TIMEDELAY);
}
} else {
Toast.makeText(getApplicationContext(),
"Starting ble for you.", Toast.LENGTH_SHORT).show();
}
}
}肯定不是的,不然就沒異常了。於是改變寫法,讓newMsg的what和obj等於原來msg的what和obj,這樣做來保持通過handler傳遞的動作的一致性,和newMsg的嶄新性。
果然,不再報異常了。
解決方法如下:
private class ChargecaseServiceHandler extends Handler {
public ChargecaseServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Command command = new Command();
command.command = msg.what;
if (msg.obj != null) {
command.data = (Bundle) msg.obj;
}
if (sIsLoopBleServiceReady) {
if (isIdle) {
switch (msg.what) {
case MESSAGE_KILL:
stopSelf();
break;
case MESSAGE_START_BLE_SCAN:
startBLEScan();
break;
case MESSAGE_CONNECT:
connect(command.data);
break;
case MESSAGE_DISCONNECT:
attemptDisconnect();
break;
case MESSAGE_RELEASE_DEVICE_ID:
clearData();
break;
case MESSAGE_INITIALIZE:
initialize();
break;
case MESSAGE_RESET_BLE:
resetBleController();
break;
case MESSAGE_STARTUP:
startup();
break;
case MESSAGE_REGISTER:
register(command.data);
break;
case MESSAGE_UNREGISTER:
unregister(command.data);
break;
case MESSAGE_RECONNECT:
reconnect();
break;
case MESSAGE_ADDCARD:
addCard(command.data);
break;
case MESSAGE_GETCARDLIST:
getCardList(command.data);
// removeMessages(MESSAGE_GETCARDLIST);
break;
case MESSAGE_GETCARDDETAIL:
getCardDetail(command.data);
break;
case MESSAGE_REMOVECARD:
removeCard(command.data);
break;
case MESSAGE_CHECK_BATTERY:
checkBattery();
break;
case MESSAGE_SET_DEFAULT_CARD:
setDefaultCard(command.data);
break;
case MESSAGE_ZAP_CARD:
zapCard(command.data);
break;
case MESSAGE_SET_LOCK_TIME:
setLockTimer(command.data);
}
} else {
Message newMsg = sServiceHandler.obtainMessage();
newMsg.what = msg.what;
newMsg.obj = msg.obj;
removeMessages(msg.what);
LogHelper.i(LogHelper.CHARGECASE_TAG, newMsg.what + "");
sServiceHandler.sendMessageDelayed(newMsg, TIMEDELAY);
}
} else {
Toast.makeText(getApplicationContext(),
"Starting ble for you.", Toast.LENGTH_SHORT).show();
}
}
}switch的消息很多,是業務需要,出現的異常也很經典,特記錄之。
PS:網上很多解決方法是把new Message()換成obtainMessage(),有的說是把obtainMessage()換成new Message(). 個人親測無法解決,或是無法解決我的問題。
PS2: 出現問題和解決問題的地方就是在倒數第二個else內。把其他的大段相關代碼貼上來的目的是方便自己明白出錯情境。請看官勿怪。
但是我的這種方法是肯定可以解決類似問題。
尋找Android手機垃圾文件的根源
Android系統中的很多安全類軟件都支持垃圾清理,但總有一些不知名文件夾能逃過類似功能的“洗禮”。那麼,我們如何根據一些蛛絲馬跡了
Android自定義控件系列四:繪制實用型的柱形圖和折線圖
概述:前幾天突然需要做兩種圖表——柱形圖、折線圖,於是第一反應是先看看網上有沒有現成的,結果有是有,但都不是想要的,而且大多數不是用純androi
Android學習筆記(十七)——使用意圖調用內置應用程序
使用意圖調用內置應用程序 1、創建一個新的Android項目並命名為Intents,在main.xml文件中添加兩個Button: 2、
Unity插件 - MeshEditor(五) 網格頂點動畫
這次加入的功能比之前幾次的實用性明顯要高些,像什麼破碎啊,融化啊,其實細想一下會發現......沒什麼卵用,模型的頂點數據還是應該交給GPU繪制才是正道,CPU刷新模型頂