android 细节之 AndroidRuntimeException:This message is already in use

今天在做项目处理消息队列的时候,遇到了这样一个问题,一个异常。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内。把其他的大段相关代码贴上来的目的是方便自己明白出错情境。请看官勿怪。

但是我的这种方法是肯定可以解决类似问题。

android 细节之 AndroidRuntimeException:This message is already in use

时间: 2024-12-23 19:36:06

android 细节之 AndroidRuntimeException:This message is already in use的相关文章

android 细节之android.view.InflateException: Binary XML file line #95: Error inflating class(out of m)

今天的异常很有意思,叫做android.view.InflateException: Binary XML file line #95: Error inflating class(out of memory) . 其实是因为out of memory,导致 xml是不可能被充气成功,因此activity的onCreate方法中, setContentView(R.layout.***)也就不可能成功调用. 他出现在我有多个教学动画,并且播放的动画,是基于imageView,imageView的

Android细节问题总结(二)

这篇博客是用来记录自己在写代码的过程中遇到的一些问题,以及解决方法,做一个总结,算是笔记吧. 1.问题描述: 以某一触发唤醒屏幕 解决方案: public static void wakeUpAndUnlock(Context context){ KeyguardManager km= (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE); KeyguardManager.KeyguardLock kl = km

Android的消息机制以及Message/MessageQueue/Handler/Looper

概览 * Message:消息.消息里面可包含简单数据.Object和Bundle,还可以包含一个Runnable(实际上可看做回调). * MessageQueue:消息队列,供Looper线程消费消息. * Looper:用于循环处理Message,一个Thread结合一个Looper来实现消息循环处理.Android App的主线程包含了Looper. * Handler:负责向当前Looper线程发送Message,并实现如何处理消息的回调,回调可放到Callback接口的实现中,也可以

android 细节之 旋转动画

Flip Animation for Android: 最近项目中用到了一个小动画,让物体实现一定的3D旋转效果,现记录如下: public class FlipAnimation extends Animation { private Camera mCamera; private View mFromView; private View mToView; private float mCenterX; private float mCenterY; private boolean mForw

android 细节之 menu 之 invalidateOptionsMenu

menu 在 android中是个非常常用的控件,以前自己做项目的时候通常都是将系统的menu相关方法在activity中直接删去,并且将主题换为fullscreen,然后再在layout中引入自己画好的新的标题栏. 实际上有更好的方法. 并不需要将系统方法删去,只需要将系统menu加上自己的图片,例如: <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://

android 细节之禁用返回键

今天项目中需要使用自己actionBar中的返回键,用的方法就是上次我记录下的父亲activity的方法 android.support.PARENT_ACTIVITY 详情请移步:http://blog.csdn.net/yiding_he/article/details/38410151 (android 细节之 menu 之 invalidateOptionsMenu) 今天的问题是禁用系统的返回键,禁用home键应该是需要permission,而且禁用后用户体验不够.所以项目中我们防止用

Android 中的消息模型(Message,MessageQueue,handle,looper)

Android 中的消息模型(Message,MessageQueue,handle,looper,) Android 中的消息通讯 1.Android 中线程的应用机制? 1)Android 中所有的耗时操作应在工作线程执行. 2)Android 中所有的UI操作应该在主线程(UI线程)执行. FAQ? 1)主线程执行执行耗时操作好吗? 不好,这样会阻塞UI操作. 2)工作执行完耗时操作,假如有数据要传递给主线程,那如何实现? 2.Android 中多线程应用时的消息模型? 使用Android

android细节之java.util.ConcurrentModificationException异常

今天在做android项目的时候,遇到了这个异常,好吧,其实平常遇到最多的异常是IllegalstateException,都是跟我们硬件相连的SDK抛出来的,把我折磨的欲生欲死啊.扯远了.说回到今天的这个异常,java.util.ConcurrentModificationException异常,一开始我愣了一下,貌似从来没遇到过这个,然后果断百度大神,这才发现: 原因是你遍历该集合时,对该集合进行了删除元素的操作导致的,如果你有删除元素的必要,建议赋值到另一个集合,然后对他进行删除操作. 偶

Android异步消息处理 Handler Looper Message关系源码分析

# 标签: 读博客 对于Handler Looper Message 之前一直只是知道理论,知其然不知所以然,看了hongyang大神的源码分析,写个总结帖. 一.概念.. Handler . Looper .Message 这三者都与Android异步消息处理线程相关的概念. 异步消息处理线程启动后会进入一个无限的循环体之中,每循环一次,从其内部的消息队列中取出一个消息,然后回调相应的消息处理函数,执行完成一个消息后则继续循环.若消息队列为空,线程则会阻塞等待. 说了这一堆,那么和Handle