本文转载自:http://blog.csdn.net/u014737138/article/details/49738827

这个问题在网上看到了太多的答案,一直提示说按照官网的api的顺序来,其实解决问题的方法不是这样的,那样没法解决问题,照着那个顺序来也米有用

 

我们得知道为什么它停止不了,为什么停止闪退了,

 

这里面有个结论就是:闪退必然是出现了控制值的错误,在Java中就是java.lang.NullXXException的错误

 

好像没有其他的原因导致闪退把,

 

stop 就删除,是因为stop的对象不存在,这个懂把,

stop对象不存在,说明对象new失败,这个懂吧,

stop的对象new失败,那就需要看new执行了哪些操作了:

  1. <strong><span style="font-size:18px;">mr=new MediaRecorder();
  2. mr.setAudioSource(MediaRecorder.AudioSource.MIC);
  3. mr.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
  4. mr.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
  5. mr.setMaxDuration(10000);
  6. mr.setOutputFile(Environment.getExternalStorageDirectory().getPath()+File.separator+"fisii77s.3gp");
  7. mr.prepare();
  8. mr.start();</span></strong>


我相信大家都是这样的做法,关键是我们前面包了一层if(mr==null)的判断了

我在代码中报错之前是这样写的:

  1. <strong><span style="font-size:18px;">  public void start(Context context, String name) {
  2. if (!Environment.getExternalStorageState().equals(
  3. android.os.Environment.MEDIA_MOUNTED)) {
  4. return;
  5. }
  6. if (mRecorder == null) {
  7. mRecorder = new MediaRecorder();
  8. mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
  9. mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
  10. mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
  11. mRecorder.setOutputFile(UtilsForChat.getMusicFilePath(context, name));
  12. try {
  13. mRecorder.prepare();
  14. mRecorder.start();
  15. mEMA = 0.0;
  16. } catch (IllegalStateException e) {
  17. System.out.print(e.getMessage());
  18. } catch (IOException e) {
  19. System.out.print(e.getMessage());
  20. }
  21. }
  22. }</span></strong>

也就是说如果对象存在,没有被销毁掉,我就不用创建了,按照常理说,确实应该这样判断对吧,可是常理一般都是错误的,

在java中 判断 一个对象是否为空确实是 == null  关键是 ==null是有谁来判断的  这个好像是说面试的时候经常这样考   我这里还是讲讲我一直那么理解的东西啊,本人还在读书,希望对以后找工作面试的时候有用 哈哈

== 这个判断是地址值比较的,equals是内容值比较的

== 这个地址值是指堆内存的,equals这个值是指在栈内存中的

 

在我们知道null判断的机制的了之后,我们就要去考虑,如果这个对象还存在,我们是否能直接用这个对象呢,经过测试答案是不行的,

 

接下来再接着说,如果我们第一次创建一个MediaRecorder对象,当我们录音结束之后肯定是停止并且释放了的,否则录音文件就不成功了,

停止,停止的是jni对象,释放,释放的jni里面的对象,同时也释放了java对象里面的栈内存的值,堆内存还保留着呢,引用为空   这里搞明白了,原因也就出来了,

关于这里面jni机制如果不懂,可以看我上篇文章,讲解的很详细

释放之后,如果马上执行第二次录音,这个时候上面的if代码就需要判断了,很明显if里面的语句是不会被执行的,因为堆内存没有被释放掉啊,但是jni里面的对象全部被释放掉了

 

这个时候如果你还用这个对象去录音,那么结果就是你对着空气说话,录的音也成了空气,然后你松开手指也就是录音对象停止的时候,无法停止了,因为jni对象是空的,不存在,怎么去停止呢,程序直接闪退,原因就是这样的了

 

解决办法就是这个时候如果你的对象不为空,你需要再重新创建一次,主要是保证你录音不会成为空气,

 

  1. <strong><span style="font-size:18px;">  public void start(Context context, String name) {
  2. if (!Environment.getExternalStorageState().equals(
  3. android.os.Environment.MEDIA_MOUNTED)) {
  4. return;
  5. }
  6. if (mRecorder == null) {
  7. mRecorder = new MediaRecorder();
  8. mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
  9. mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
  10. mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
  11. mRecorder.setOutputFile(UtilsForChat.getMusicFilePath(context, name));
  12. try {
  13. mRecorder.prepare();
  14. mRecorder.start();
  15. mEMA = 0.0;
  16. } catch (IllegalStateException e) {
  17. System.out.print(e.getMessage());
  18. } catch (IOException e) {
  19. System.out.print(e.getMessage());
  20. }
  21. }else{
  22. stop();
  23. mRecorder = new MediaRecorder();
  24. mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
  25. mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
  26. mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
  27. mRecorder.setOutputFile(UtilsForChat.getMusicFilePath(context, name));
  28. try {
  29. mRecorder.prepare();
  30. } catch (IllegalStateException | IOException e) {
  31. // TODO Auto-generated catch block
  32. e.printStackTrace();
  33. }
  34. mRecorder.start();
  35. }
  36. }</span></strong>


代码就变成这样了,其实,这里面更简单点就是每次不判断,进来直接把原来的停止,然后再创建 可以省掉很多代码了

 

然后就是stop函数,一定要写对,否则还是报错的哦:

 

  1. <strong><span style="font-size:18px;">  public void stop() {
  2. if (mRecorder != null) {
  3. try {
  4. mRecorder.stop();
  5. } catch (IllegalStateException e) {
  6. // TODO 如果当前java状态和jni里面的状态不一致,
  7. //e.printStackTrace();
  8. mRecorder = null;
  9. mRecorder = new MediaRecorder();
  10. }
  11. mRecorder.release();
  12. mRecorder = null;
  13. }
  14. }</span></strong>


这里面有人肯定问,你这里面stop已经搞了异常抛出,为什么上面的创建还加上else那样的代码呢,

 

这里面也是机型的原因然后导致我最终还是保留了这段代码   因为要保证你说的话,录音的音不会成为空气啊  这也是很重要的bug啊

Android 使用MediaRecorder录音调用stop()方法的时候报错【转】的更多相关文章

  1. java调用本地方法的时候报错 could not find the main class:xx.program will exit

    如图所示,当在java调用本地方法的时候报错 我的解决办法是把dll文件放到System.out.println(System.getProperty("java.library.path& ...

  2. Android和JavaScript相互调用的方法

    转载地址:http://www.jb51.net/article/77206.htm 这篇文章主要介绍了Android和JavaScript相互调用的方法,实例分析了Android的WebView执行 ...

  3. ajax 调用 .net core WebAPI,报错 400 (Bad Request) Unexpected character encountered while parsing value

    此文由博主前两天的提问及 dudu 的回答整理,地址:https://q.cnblogs.com/list/myquestion 情况说明 基于 .net core 写了一个 Web API,用 po ...

  4. Android 使用MediaRecorder录音

    package com.example.HyyRecord; import android.app.Activity; import android.content.Intent; import an ...

  5. Android JNI中C调用Java方法

    背景需求 我们需要在JNI的C代码调用Java代码.实现原理:使用JNI提供的反射借口来反射得到Java方法,进行调用. JNI关键方法讲解. 1. 在同一个类中,调用其他方法 JNIEXPORT v ...

  6. Android Studio ERROR: x86 emulation currently requires hardware acceleration!报错解决傻瓜教程~

    很早之前就碰到过Android Studio模拟器无法启动的问题,今天终于尝试去解决了下,下面将我解决的方法记录下. 模拟器报错信息为: emulator: ERROR: x86 emulation ...

  7. vc调用BCB的dll 参数传递 报错

    可能原因: 调用方式约定不一致. 函数调用约定如下: 1. __cdecl:C 和 C++ 程序的缺省调用规范. 2. __stdcall:标准调用约定(即WINAPI调用约定),也就是pascal调 ...

  8. 执行发送邮件Send方法时,报错:邮箱不可用。 服务器响应为: 5.7.1 Unable to relay for xxx@xxx.com

    .net代码在执行发送邮件Send方法时,往往出现这个的报错: 邮箱不可用. 服务器响应为: 5.7.1 Unable to relay for xxx@xxx.com 这个问题应该是smtp的设置问 ...

  9. fetch get方法的时候报错

    fetch 报错 Failed to execute 'fetch' on 'Window': Request with GET/HEAD method cannot have body. 翻译过来就 ...

随机推荐

  1. vue项目 build之后发布到服务器index.html页面空白解决方法

    第一部分 之前一直不太理解为什么要使用vue+webapck,还有在使用了vue-cli之后会用到后台,即vue-cli自动帮我们安装了express服务器,在本地服务器上运行,因为我们希望可以模拟在 ...

  2. Redis系列(八)--缓存穿透、雪崩、更新策略

    1.缓存更新策略 1.LRU/LFU/FIFO算法剔除:例如maxmemory-policy 2.超时剔除,过期时间expire,对于一些用户可以容忍延时更新的数据,例如文章简介内容改了几个字 3.主 ...

  3. ios xmpp 发送语音图片解决方案

    ios xmpp 发送语音,图片解决方案,有需要的朋友可以参考下. 目前做IM多是用的xmpp. 因为项目需求需要实现语音和图片的发送. 发送语音图片有三种方法. 1,xmpp smack.文件传输方 ...

  4. UVA-1599 Ideal Path(双向BFS)

    题目: 给一个n个点m条边(2≤m≤100000, 1≤m≤200000)的无向图,每条边上都涂有一种颜色(用1到1000000000表示).求从结点1到结点n的一条路径, 使得经过的边数尽量少,在此 ...

  5. <MyBatis>入门一 HelloWorld

    1.HelloWorld 导入依赖 <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependen ...

  6. TestNG分组测试

    分为方法的分组和类的分组: GroupsOnMethod类: package com.janson.groups; import org.testng.annotations.Test; public ...

  7. python爬虫30 | scrapy后续,把「糗事百科」的段子爬下来然后存到数据库中

    上回我们说到 python爬虫29 | 使用scrapy爬取糗事百科的例子,告诉你它有多厉害! WOW!! scrapy awesome!! 怎么会有这么牛逼的框架 wow!! awesome!! 用 ...

  8. i2c中start和restart的区别

    有的硬件芯片提供了一个个寄存器,供我们很好的操作i2c,但是,在用的时候,我们是不知道他到地是怎么操作的,下边,我就探讨下i2c中的start和restart的区别. start是在scl是高电平的时 ...

  9. No buffer space available错误解决方案

    生产环境,突然爆发问题,网络正常,但是报网络不通错误,重启tomcat立刻好使 开始以为是tomcat的问题,调查了很久,后来加上堆栈日志才发现 简单来说,就是1-4分钟之内,使用了大量的http请求 ...

  10. 【07】AngularJS Filters

    AngularJS Filters 过滤器可以使用一个管道字符(|)添加到表达式和指令中. AngularJS 过滤器 AngularJS 过滤器可用于转换数据: 过滤器 描述 currency[ˈk ...