android中java.lang.IllegalStateException异常产生的原因及解决办法

11-09 13:33:56.080: E/MediaRecorder(19865): stop called in an invalid state: 0
11-09 13:33:56.080: I/MediaRecorder(19865): stop
11-09 13:33:56.080: E/MediaRecorder(19865): stop called in an invalid state: 1
11-09 13:33:56.080: E/InputEventReceiver(19865): Exception dispatching input event.
11-09 13:33:56.080: E/MessageQueue-JNI(19865): Exception in MessageQueue callback: handleReceiveCallback
11-09 13:33:56.080: E/MessageQueue-JNI(19865): java.lang.IllegalStateException
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.media.MediaRecorder.native_stop(Native Method)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.media.MediaRecorder.stop(MediaRecorder.java:1127)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at com.jarvis.message.SoundMeter.stop(SoundMeter.java:64)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at com.jarvis.message.SoundMeter.start(SoundMeter.java:38)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at com.jarvis.user.RusumeReadView.start(RusumeReadView.java:522)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at com.jarvis.user.RusumeReadView.access$26(RusumeReadView.java:520)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at com.jarvis.user.RusumeReadView$17.onTouch(RusumeReadView.java:469)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.View.dispatchTouchEvent(View.java:8287)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2324)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2011)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2324)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2011)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2324)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2011)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2324)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2011)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2324)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2011)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2324)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2011)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2324)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2011)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2324)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2011)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2324)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2011)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2324)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2011)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2324)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2011)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2324)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2011)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2324)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2011)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2345)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1708)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.app.Activity.dispatchTouchEvent(Activity.java:2797)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2306)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.View.dispatchPointerEvent(View.java:8483)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4291)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4157)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3662)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3715)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3681)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3791)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3689)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3848)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3662)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3715)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3681)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3689)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3662)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:5978)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:5952)
11-09 13:33:56.080: E/MessageQueue-JNI(19865): 	at android.view.ViewRootImpl.enqueueInputEvent(ViewRootIm


出现这个问题真的很难受,搞了好久,其实不同的机型有不同的效果,我在魅族 手机 华硕手机  华为p8上都没有出现这样的问题

在小米2s 在华为荣耀7 上都出现了这样的bug  


接下来是分析真正的问题原因所在 解决办法很简单,就是捕获这个异常,因为是空的,再重新new下,然后接着释放就可以了

IllegalStateException这个异常它是指“非法的状态”。

android的MediaRecorder 和MediaPlayer API中用到了JNI,也就是我们的java代码是要调用native的C++方法的

MediaRecorder ,MediaPlayer 是用c++实现的),

出现这个异常,就是因为我们java里面的MediaRecorder ,MediaPlayer 对象的状态和native的对象状态发生了不一致。


问题的本质就是这样的,那什么叫状态不一致,我们得用代码中来解析下才能看的懂了:


使用的时候我们应该都知道,MediaRecorder 和MediaPlayer 用的方法有哪些了

if (mMediaPlayer.isPlaying()) {
				mMediaPlayer.stop();
			}
			mMediaPlayer.reset();
			mMediaPlayer.setDataSource(name);
			mMediaPlayer.prepare();
			mMediaPlayer.start();

		if (mRecorder == null) {
			mRecorder = new MediaRecorder();
			mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
			mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
			mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
			mRecorder.setOutputFile(UtilsForChat.getMusicFilePath(context, name));
			try {
				mRecorder.prepare();
				mRecorder.start();

				mEMA = 0.0;
			} catch (IllegalStateException e) {
				System.out.print(e.getMessage());
			} catch (IOException e) {
				System.out.print(e.getMessage());
			}

		}
mRecorder.stop();
mRecorder.release();

我相信大家都对这些方法都不陌生的,只是需要我们知道他们的顺序,但是仅仅知道顺序肯定是没有用的,

因为你照样会产生上面的错误  比如专业的错误:

切换录像暂停过快导致stop failed.
java.lang.RuntimeException: stop failed.
at android.media.MediaRecorder.stop(Native Method)

原因如下:
在调用start()后马上调用stop(),时由于没有生成有效的音频或是视频数据。解决方法:让线程睡眠一定的时间,在测试后发现1秒几乎是最短时间。

这个错误我下篇文章再介绍我遇到的情况是什么样的,这里还是回到本bug的点子上


出现标题的bug就是stop release isPlaying这些函数会出现问题,而出现的问题就是java对象状态和NAtive对象状态不一致导致无法停止,无法释放,无法播放


再往里面说,就是这样的:当我们第一次申请了一个MediaRecorder 录音对象,我们在java中释放掉了,那么谁能告诉我释放的是谁的对象吗,我当时也纠结了,不知道,后来查阅别人说的,释放的是jni的对象,而java对象只是把栈内存里面释放了,其实这里面我到现在还是没有搞明白是不是这个意思,这样就导致了本地对象的堆内存还是存在的,而jni对象里面什么都没有了,能明白这个意思把,就导致的不一致


stop出现的原因就是:你想停止它(停止的对象是jni里面的),可惜的是你根本没有这个对象你怎么停止呢  这不就是出现了对象不一致了吗

isPlaying出现的原因也就是:你想判断他是否正在播放,那么如果你根本就不存在,我怎么去判断呢,

release,也是一样,不过这个里面保持总是在stop后面,所以出现的少


问题分析到这里来了,我想大家应该都会解决了,只要找到这个异常,try下然后把java对象申请出来,不就可以使得jni和java对象一致了吗,然后你再停止就ok拉

代码就是这样的:

	public void stop() {
		if (mRecorder != null) {
			try {
				mRecorder.stop();
			} catch (IllegalStateException e) {
				// TODO 如果当前java状态和jni里面的状态不一致,
				//e.printStackTrace();
				mRecorder = null;
				mRecorder = new MediaRecorder();
			}
			mRecorder.release();
			mRecorder = null;
		}
	}

对于在java中:mRecorder = new MediaRecorder(); 我相信这句代码大家应该都知道,java机制是怎么样处理的

java会分别在堆内存和栈内存中操作,一个是内容,一个是地址,内容引用地址或者叫指向地址值

这样加上try之后,我发现录音你不管怎么操作都没有问题了,后来我想了下,这个代码顺序应该跟api中还是不一致


	public void stop() {
		if (mRecorder != null) {
			try {
				mRecorder.stop();
			} catch (IllegalStateException e) {
				// TODO 如果当前java状态和jni里面的状态不一致,
				//e.printStackTrace();
				mRecorder = null;
				mRecorder = new MediaRecorder();
				mRecorder.stop();
			}
			mRecorder.release();
			mRecorder = null;
		}
	}

这个代码多了一行  stop()  我没有测试,谁可以看看,

整个问题就这样解决了



  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值