今天在做项目处理消息队列的时候。遇到了这样一个问题。一个异常。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究竟是不是一个新的message呢?
肯定不是的,不然就没异常了。于是改变写法,让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内。把其它的大段相关代码贴上来的目的是方便自己明确出错情境。请看官勿怪。
可是我的这样的方法是肯定能够解决类似问题。