热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Android使用MediaRecorder实现录音及播放

这篇文章主要为大家详细介绍了Android使用MediaRecorder实现录音及播放,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

现在项目中有使用到音视频相关技术,在参考了网上各种大牛的资料及根据自己项目实际情况(兼容安卓6.0以上版本动态权限管理等),把声音录制及播放相关代码做个记录。

public class MediaRecorderActivity extends BaseActivity {
 private Button start_tv;
 private ListView listView;
 //线程操作
 private ExecutorService mExecutorService;
 //录音API
 private MediaRecorder mMediaRecorder;
 //录音开始时间与结束时间
 private long startTime, endTime;
 //录音所保存的文件
 private File mAudioFile;
 //文件列表数据
 private List dataList;
 //录音文件数据列表适配器
 private AudioAdapter mAudioAdapter;
 //录音文件保存位置
 private String mFilePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/audio/";
 //当前是否正在播放
 private volatile boolean isPlaying;
 //播放音频文件API
 private MediaPlayer mediaPlayer;
 //使用Handler更新UI线程
 private Handler mHandler = new Handler() {
  @Override
  public void handleMessage(Message msg) {
   super.handleMessage(msg);
   switch (msg.what) {
    case Constant.RECORD_SUCCESS:
     //录音成功,展示数据
     if (null == mAudioAdapter) {
      mAudioAdapter = new AudioAdapter(MediaRecorderActivity.this, dataList, R.layout.file_item_layout);
     }
     listView.setAdapter(mAudioAdapter);
     break;
    //录音失败
    case Constant.RECORD_FAIL:
     showToastMsg(getString(R.string.record_fail));
     break;
    //录音时间太短
    case Constant.RECORD_TOO_SHORT:
     showToastMsg(getString(R.string.time_too_short));
     break;
    case Constant.PLAY_COMPLETION:
     showToastMsg(getString(R.string.play_over));
     break;
    case Constant.PLAY_ERROR:
     showToastMsg(getString(R.string.play_error));
     break;

   }
  }
 };

 @Override
 protected void setWindowView() {
  setContentView(R.layout.activity_record);
  //录音及播放要使用单线程操作
  mExecutorService = Executors.newSingleThreadExecutor();
  dataList = new ArrayList<>();
 }

 @Override
 protected void initViews() {
  this.start_tv = (Button) findViewById(R.id.start_tv);
  this.listView = (ListView) findViewById(R.id.listview);
 }

 @Override
 protected void initEvents() {
  //类似微信等应用按住说话进行录音,所以用OnTouch事件
  this.start_tv.setOnTouchListener(new View.OnTouchListener() {
   @Override
   public boolean onTouch(View view, MotionEvent motionEvent) {
    switch (motionEvent.getAction()) {
     //按下操作
     case MotionEvent.ACTION_DOWN:
      //安卓6.0以上录音相应权限处理
      if (Build.VERSION.SDK_INT > 22) {
       permissionForM();
      } else {
       startRecord();
      }
      break;
     //松开操作
     case MotionEvent.ACTION_CANCEL:
     case MotionEvent.ACTION_UP:
      stopRecord();
      break;
    }
    //对OnTouch事件做了处理,返回true
    return true;
   }
  });
  //点击播放对应的录音文件
  this.listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
   @Override
   public void onItemClick(AdapterView<&#63;> adapterView, View view, int i, long l) {
    //使用MediaPlayer播放声音文件
    startPlay(dataList.get(i).getFile());
   }
  });
 }


 /**
  * @description 开始进行录音
  * @author ldm
  * @time 2017/2/9 9:18
  */
 private void startRecord() {
  start_tv.setText(R.string.stop_by_up);
  start_tv.setBackgroundResource(R.drawable.bg_gray_round);
  //异步任务执行录音操作
  mExecutorService.submit(new Runnable() {
   @Override
   public void run() {
    //播放前释放资源
    releaseRecorder();
    //执行录音操作
    recordOperation();
   }
  });
 }

 /**
  * @description 录音失败处理
  * @author ldm
  * @time 2017/2/9 9:35
  */
 private void recordFail() {
  mAudioFile = null;
  mHandler.sendEmptyMessage(Constant.RECORD_FAIL);
 }

 /**
  * @description 录音操作
  * @author ldm
  * @time 2017/2/9 9:34
  */
 private void recordOperation() {
  //创建MediaRecorder对象
  mMediaRecorder = new MediaRecorder();
  //创建录音文件,.m4a为MPEG-4音频标准的文件的扩展名
  mAudioFile = new File(mFilePath + System.currentTimeMillis() + ".m4a");
  //创建父文件夹
  mAudioFile.getParentFile().mkdirs();
  try {
   //创建文件
   mAudioFile.createNewFile();
   //配置mMediaRecorder相应参数
   //从麦克风采集声音数据
   mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
   //设置保存文件格式为MP4
   mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
   //设置采样频率,44100是所有安卓设备都支持的频率,频率越高,音质越好,当然文件越大
   mMediaRecorder.setAudioSamplingRate(44100);
   //设置声音数据编码格式,音频通用格式是AAC
   mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
   //设置编码频率
   mMediaRecorder.setAudioEncodingBitRate(96000);
   //设置录音保存的文件
   mMediaRecorder.setOutputFile(mAudioFile.getAbsolutePath());
   //开始录音
   mMediaRecorder.prepare();
   mMediaRecorder.start();
   //记录开始录音时间
   startTime = System.currentTimeMillis();
  } catch (Exception e) {
   e.printStackTrace();
   recordFail();
  }
 }


 /**
  * @description 结束录音操作
  * @author ldm
  * @time 2017/2/9 9:18
  */
 private void stopRecord() {
  start_tv.setText(R.string.speak_by_press);
  start_tv.setBackgroundResource(R.drawable.bg_white_round);
  //停止录音
  mMediaRecorder.stop();
  //记录停止时间
  endTime = System.currentTimeMillis();
  //录音时间处理,比如只有大于2秒的录音才算成功
  int time = (int) ((endTime - startTime) / 1000);
  if (time >= 3) {
   //录音成功,添加数据
   FileBean bean = new FileBean();
   bean.setFile(mAudioFile);
   bean.setFileLength(time);
   dataList.add(bean);
   //录音成功,发Message
   mHandler.sendEmptyMessage(Constant.RECORD_SUCCESS);
  } else {
   mAudioFile = null;
   mHandler.sendEmptyMessage(Constant.RECORD_TOO_SHORT);
  }
  //录音完成释放资源
  releaseRecorder();
 }

 /**
  * @description 翻放录音相关资源
  * @author ldm
  * @time 2017/2/9 9:33
  */
 private void releaseRecorder() {
  if (null != mMediaRecorder) {
   mMediaRecorder.release();
   mMediaRecorder = null;
  }
 }

 @Override
 public void onClick(View view) {

 }

 @Override
 protected void onDestroy() {
  super.onDestroy();
  //页面销毁,线程要关闭
  mExecutorService.shutdownNow();
 }
 /*******6.0以上版本手机权限处理***************************/
 /**
  * @description 兼容手机6.0权限管理
  * @author ldm
  * @time 2016/5/24 14:59
  */
 private void permissionForM() {
  if (ContextCompat.checkSelfPermission(this,
    Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this,
    Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {

   ActivityCompat.requestPermissions(this,
     new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE},
     Constant.PERMISSIONS_REQUEST_FOR_AUDIO);
  } else {
   startRecord();
  }

 }

 @Override
 public void onRequestPermissionsResult(int requestCode,
           @NonNull String[] permissions, @NonNull int[] grantResults) {

  if (requestCode == Constant.PERMISSIONS_REQUEST_FOR_AUDIO) {
   if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
    startRecord();
   }
   return;
  }
  super.onRequestPermissionsResult(requestCode, permissions, grantResults);
 }

 /**
  * @description 播放音频
  * @author ldm
  * @time 2017/2/9 16:54
  */
 private void playAudio(final File mFile) {
  if (null != mFile && !isPlaying) {
   isPlaying = true;
   mExecutorService.submit(new Runnable() {
    @Override
    public void run() {
     startPlay(mFile);
    }
   });
  }
 }

 /**
  * @description 开始播放音频文件
  * @author ldm
  * @time 2017/2/9 16:56
  */
 private void startPlay(File mFile) {
  try {
   //初始化播放器
   mediaPlayer = new MediaPlayer();
   //设置播放音频数据文件
   mediaPlayer.setDataSource(mFile.getAbsolutePath());
   //设置播放监听事件
   mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
    @Override
    public void onCompletion(MediaPlayer mediaPlayer) {
     //播放完成
     playEndOrFail(true);
    }
   });
   //播放发生错误监听事件
   mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
    @Override
    public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {
     playEndOrFail(false);
     return true;
    }
   });
   //播放器音量配置
   mediaPlayer.setVolume(1, 1);
   //是否循环播放
   mediaPlayer.setLooping(false);
   //准备及播放
   mediaPlayer.prepare();
   mediaPlayer.start();
  } catch (IOException e) {
   e.printStackTrace();
   //播放失败正理
   playEndOrFail(false);
  }

 }

 /**
  * @description 停止播放或播放失败处理
  * @author ldm
  * @time 2017/2/9 16:58
  */
 private void playEndOrFail(boolean isEnd) {
  isPlaying = false;
  if (isEnd) {
   mHandler.sendEmptyMessage(Constant.PLAY_COMPLETION);
  } else {
   mHandler.sendEmptyMessage(Constant.PLAY_ERROR);
  }
  if (null != mediaPlayer) {
   mediaPlayer.setOnCompletionListener(null);
   mediaPlayer.setOnErrorListener(null);
   mediaPlayer.stop();
   mediaPlayer.reset();
   mediaPlayer.release();
   mediaPlayer = null;
  }
 }
}

页面布局



 

对应资源文件strings.xml:


 mediarecorder
 录音失败
 时间太短,请重新录音
 播放完成
 抱歉,播放发生异常
 松开停止录音
 按住说话
 开始录音
 停止录音

录音相关权限 :





安卓录制播放音频:https://github.com/ldm520/Android_Media

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 解决微信电脑版无法刷朋友圈问题:使用安卓远程投屏方案
    在工作期间想要浏览微信和朋友圈却不太方便?虽然微信电脑版目前不支持直接刷朋友圈,但通过远程投屏技术,可以轻松实现在电脑上操作安卓设备的功能。 ... [详细]
  • 在Linux系统中配置并启动ActiveMQ
    本文详细介绍了如何在Linux环境中安装和配置ActiveMQ,包括端口开放及防火墙设置。通过本文,您可以掌握完整的ActiveMQ部署流程,确保其在网络环境中正常运行。 ... [详细]
  • Android LED 数字字体的应用与实现
    本文介绍了一种适用于 Android 应用的 LED 数字字体(digital font),并详细描述了其在 UI 设计中的应用场景及其实现方法。这种字体常用于视频、广告倒计时等场景,能够增强视觉效果。 ... [详细]
  • RecyclerView初步学习(一)
    RecyclerView初步学习(一)ReCyclerView提供了一种插件式的编程模式,除了提供ViewHolder缓存模式,还可以自定义动画,分割符,布局样式,相比于传统的ListVi ... [详细]
  • 扫描线三巨头 hdu1928hdu 1255  hdu 1542 [POJ 1151]
    学习链接:http:blog.csdn.netlwt36articledetails48908031学习扫描线主要学习的是一种扫描的思想,后期可以求解很 ... [详细]
  • 从零开始构建完整手机站:Vue CLI 3 实战指南(第一部分)
    本系列教程将引导您使用 Vue CLI 3 构建一个功能齐全的移动应用。我们将深入探讨项目中涉及的每一个知识点,并确保这些内容与实际工作中的需求紧密结合。 ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • Android 渐变圆环加载控件实现
    本文介绍了如何在 Android 中创建一个自定义的渐变圆环加载控件,该控件已在多个知名应用中使用。我们将详细探讨其工作原理和实现方法。 ... [详细]
  • XNA 3.0 游戏编程:从 XML 文件加载数据
    本文介绍如何在 XNA 3.0 游戏项目中从 XML 文件加载数据。我们将探讨如何将 XML 数据序列化为二进制文件,并通过内容管道加载到游戏中。此外,还会涉及自定义类型读取器和写入器的实现。 ... [详细]
  • 本文介绍如何通过SQL查询从JDE(JD Edwards)系统中提取所有字典数据,涵盖关键表的关联和字段选择。具体包括F0004和F0005系列表的数据提取方法。 ... [详细]
  • 本文详细介绍了如何通过命令行启动MySQL服务,包括打开命令提示符窗口、进入MySQL的bin目录、输入正确的连接命令以及注意事项。文中还提供了更多相关命令的资源链接。 ... [详细]
  • 本文介绍如何使用 NSTimer 实现倒计时功能,详细讲解了初始化方法、参数配置以及具体实现步骤。通过示例代码展示如何创建和管理定时器,确保在指定时间间隔内执行特定任务。 ... [详细]
  • 本文介绍了在Windows环境下使用pydoc工具的方法,并详细解释了如何通过命令行和浏览器查看Python内置函数的文档。此外,还提供了关于raw_input和open函数的具体用法和功能说明。 ... [详细]
  • 网络运维工程师负责确保企业IT基础设施的稳定运行,保障业务连续性和数据安全。他们需要具备多种技能,包括搭建和维护网络环境、监控系统性能、处理突发事件等。本文将探讨网络运维工程师的职业前景及其平均薪酬水平。 ... [详细]
author-avatar
胆小的女屌丝
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有