欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android录制声音文件(音频)并播放

程序员文章站 2024-02-28 15:36:10
本文实例为大家分享了android录制音频文件的具体代码,供大家参考,具体内容如下 1、这个demo中没有对多次点击同一个声音文件做详细处理,偶尔会有崩溃,用的时候需...

本文实例为大家分享了android录制音频文件的具体代码,供大家参考,具体内容如下

1、这个demo中没有对多次点击同一个声音文件做详细处理,偶尔会有崩溃,用的时候需要注意。

2、按住录音按钮录音过程中,只对竖直方向处理了一下,水平方向没写;

3、没有做删除某个声音文件的操作,但是测试的时候实现了功能,需要用到的话,在mainactivity—>onitemclick中的todo中有详细说明;

4、这只是个demo,如果要在项目中使用,先写出demo,没问题了,再引入项目,在写成demo后,在真机上运行的时候,如果出现获取录音权限,最好选择“允许”,如果拒绝,可能会崩溃。

记得打开手机运行录音的权限

先来效果图:

Android录制声音文件(音频)并播放

目录结构:

Android录制声音文件(音频)并播放

1、添加权限:

 <uses-permission android:name="android.permission.record_audio"/>
 <uses-permission android:name="android.permission.wake_lock"/>
 <uses-permission android:name="android.permission.modify_audio_settings"/>
 <uses-permission android:name="android.permission.vibrate"/>
 <uses-permission android:name="android.permission.write_settings"/>
 <uses-permission android:name="android.permission.interact_across_users_full"/>
 <uses-permission android:name="android.permission.receive_boot_completed"/>
 <uses-permission android:name="android.permission.access_fine_location"/>
 <uses-permission android:name="android.permission.call_phone"/>
 <uses-permission android:name="android.permission.read_external_storage"/>
 <uses-permission android:name="android.permission.internet" />
 <uses-permission android:name="android.permission.write_external_storage" />
 <uses-permission android:name="android.permission.mount_unmount_filesystems" />

2、新建mediarecorderutils,复制以下源码:

package com.chen.voicedemo;

import android.media.mediarecorder;
import android.os.handler;
import android.util.log;
import android.widget.imageview;

import java.io.file;

/**
 * 录音工具类
 */
public class mediarecorderutils {

 private static mediarecorder recorder;
 static mediarecorderutils mediarecorderutils;
 static imageview mimageview;
 private string path;

 /**
  * 获得单例对象,传入一个显示音量大小的imageview对象,如不需要显示可以传null
  */
 public static mediarecorderutils getinstence(imageview imageview) {
  if (mediarecorderutils == null) {
   mediarecorderutils = new mediarecorderutils();
  }
  mimageview = imageview;
  return mediarecorderutils;
 }

 /**
  * 获得音频路径
  */
 public string getpath() {
  return path;
 }

 /**
  * 初始化
  */
 private void init() {

  recorder = new mediarecorder();// new出mediarecorder对象
  recorder.setaudiosource(mediarecorder.audiosource.mic);
  // 设置mediarecorder的音频源为麦克风 
  recorder.setoutputformat(mediarecorder.outputformat.raw_amr);
  // 设置mediarecorder录制的音频格式 
  recorder.setaudioencoder(mediarecorder.audioencoder.amr_nb);
  // 设置mediarecorder录制音频的编码为amr. 
  file file = new file(utils.image_sdcard_mader);
  if (!file.exists()) {
   file.mkdirs();
  }
  path = utils.image_sdcard_mader + utils.getvoicefilename() + "stock.amr";
  recorder.setoutputfile(path);
  // 设置录制好的音频文件保存路径 
  try {
   recorder.prepare();// 准备录制 
  } catch (exception e) {
   e.printstacktrace();
  }
 }

 /**
  * 开始录音
  */
 public void mediarecorderstart() {
  init();
  try {
   recorder.start();
   flag = true;
   if (mimageview != null) {
    updatemicstatus();
   }
  } catch (exception e) {
   e.printstacktrace();
   log.e("chen", "录制失败");
  }
 }

 /**
  * 停止录音
  */
 public void mediarecorderstop() {
  try {
   recorder.stop();
   recorder.release(); //释放资源
   flag = false;
   mimageview = null;
   recorder = null;
  } catch (exception e) {
   e.tostring();
  }

 }

 /**
  * 删除已录制的音频
  */
 public void mediarecorderdelete() {
  file file = new file(path);
  if (file.isfile()) {
   file.delete();
  }
  file.exists();
 }

 ;

 private final handler mhandler = new handler();
 private runnable mupdatemicstatustimer = new runnable() {
  public void run() {
   updatemicstatus();
  }
 };
 private int base = 1;
 private int space = 1000;// 间隔取样时间
 private boolean flag = true;

 /**
  * 更新话筒状态
  */
 private void updatemicstatus() {
  if (recorder != null) {
   double ratio = (double) recorder.getmaxamplitude() / base;
   double db = 0;// 分贝
   if (ratio > 1) {
    db = 20 * math.log10(ratio);
   }
   int i = (int) db / 10;
   switch (i) {
    case 1:
     mimageview.setimageresource(r.drawable.rc_ic_volume_1);
     break;
    case 2:
     mimageview.setimageresource(r.drawable.rc_ic_volume_2);
     break;
    case 3:
     mimageview.setimageresource(r.drawable.rc_ic_volume_3);
     break;
    case 4:
     mimageview.setimageresource(r.drawable.rc_ic_volume_4);
     break;
    case 5:
     mimageview.setimageresource(r.drawable.rc_ic_volume_5);
     break;
    case 6:
     mimageview.setimageresource(r.drawable.rc_ic_volume_6);
     break;
    case 7:
     mimageview.setimageresource(r.drawable.rc_ic_volume_7);
     break;
    case 8:
     mimageview.setimageresource(r.drawable.rc_ic_volume_8);
     break;
   }
   if (flag) {
    mhandler.postdelayed(mupdatemicstatustimer, space);
   }
  }
 }

}

3、创建mychronometer,复制以下代码

package com.chen.voicedemo;

import android.annotation.suppresslint;
import android.content.context;
import android.os.handler;
import android.os.message;
import android.os.systemclock;
import android.util.attributeset;
import android.view.accessibility.accessibilityevent;
import android.view.accessibility.accessibilitynodeinfo;
import android.widget.textview;

public class mychronometer extends textview {

 private static final string tag = "mychronometer";

 /**
  * a callback that notifies when the mychronometer has incremented on its
  * own.
  */
 public interface onmychronometerticklistener {

  /**
   * notification that the mychronometer has changed.
   */
  void onmychronometertick(int time);

 }

 public interface onmychronometertimelistener {

  /**
   * notification that the mychronometer has changed.
   */
  void onmychronometertimelistener(int time);

 }

 private onmychronometertimelistener onmychronometertimelistener;

 private long mbase;
 private boolean mvisible;
 private boolean mstarted;
 private boolean mrunning;
 private onmychronometerticklistener monmychronometerticklistener;
 private long now_time;

 private static final int tick_what = 2;

 /**
  * initialize this mychronometer object. sets the base to the current time.
  */
 public mychronometer(context context) {
  this(context, null, 0);
 }

 /**
  * initialize with standard view layout information. sets the base to the
  * current time.
  */
 public mychronometer(context context, attributeset attrs) {
  this(context, attrs, 0);
 }

 /**
  * initialize with standard view layout information and style. sets the base
  * to the current time.
  */
 public mychronometer(context context, attributeset attrs, int defstyle) {
  super(context, attrs, defstyle);
  init();
 }

 private void init() {
  mbase = systemclock.elapsedrealtime();
  updatetext(mbase);
 }

 /**
  * set the time that the count-up timer is in reference to.
  *
  * @param base use the {@link systemclock#elapsedrealtime} time base.
  */
 public void setbase(long base) {
  mbase = base;
  updatetext(systemclock.elapsedrealtime());
 }

 /**
  * sets the listener to be called when the mychronometer changes.
  *
  * @param listener the listener.
  */
 public void setonmychronometerticklistener(onmychronometerticklistener listener) {
  monmychronometerticklistener = listener;
 }

 public void setonmychronometertimelistener(onmychronometertimelistener listener) {
  onmychronometertimelistener = listener;
 }

 /**
  * start counting up. this does not affect the base as set from
  * {@link #setbase}, just the view display.
  * <p/>
  * mychronometer works by regularly scheduling messages to the handler, even
  * when the widget is not visible. to make sure resource leaks do not occur,
  * the user should make sure that each start() call has a reciprocal call to
  * {@link #stop}.
  */
 public void start() {
  mstarted = true;
  updaterunning();
 }

 /**
  * stop counting up. this does not affect the base as set from
  * {@link #setbase}, just the view display.
  * <p/>
  * this stops the messages to the handler, effectively releasing resources
  * that would be held as the mychronometer is running, via {@link #start}.
  */
 public void stop() {
  mstarted = false;
  updaterunning();
  now_time /= 10;
  if (onmychronometertimelistener != null) {
   onmychronometertimelistener.onmychronometertimelistener((int) now_time);
  }
 }

 @override
 protected void ondetachedfromwindow() {
  super.ondetachedfromwindow();
  mvisible = false;
  updaterunning();
 }

 @override
 protected void onwindowvisibilitychanged(int visibility) {
  super.onwindowvisibilitychanged(visibility);
  mvisible = visibility == visible;
  updaterunning();
 }

 private synchronized void updatetext(long now) {

  long seconds = now - mbase;
  seconds /= 10;
  now_time = seconds;

  int time_m = (int) (seconds / 100);
  if (monmychronometerticklistener != null) {
   monmychronometerticklistener.onmychronometertick(time_m);
  }
  int time_s = (int) (seconds % 100);
  settext(time_m + "");

 }

 private void updaterunning() {
  boolean running = mvisible && mstarted;
  if (running != mrunning) {
   if (running) {
    updatetext(systemclock.elapsedrealtime());
    mhandler.sendmessagedelayed(message.obtain(mhandler, tick_what), 1000);
   } else {
    mhandler.removemessages(tick_what);
   }
   mrunning = running;
  }
 }

 private handler mhandler = new handler() {
  public void handlemessage(message m) {
   if (mrunning) {
    updatetext(systemclock.elapsedrealtime());
    sendmessagedelayed(message.obtain(this, tick_what), 1000);
   }
  }
 };

 @suppresslint("newapi")
 @override
 public void oninitializeaccessibilityevent(accessibilityevent event) {
  super.oninitializeaccessibilityevent(event);
  event.setclassname(mychronometer.class.getname());
 }

 @suppresslint("newapi")
 @override
 public void oninitializeaccessibilitynodeinfo(accessibilitynodeinfo info) {
  super.oninitializeaccessibilitynodeinfo(info);
  info.setclassname(mychronometer.class.getname());
 }

}

4、创建工具类

package com.chen.voicedemo;

import android.manifest;
import android.content.context;
import android.content.pm.packagemanager;
import android.os.environment;
import android.support.v4.content.contextcompat;
import android.widget.toast;

import java.io.file;
import java.text.simpledateformat;
import java.util.arraylist;

/**
 * 工具
 */
public class utils {

 /**
  * sd卡下语音目录
  */
 public static final string image_sdcard_mader = environment
   .getexternalstoragedirectory()
   + "/chen/voice/";

 /**
  * 检查录音权限6.0
  */
 public static boolean checkvoice(context context) {

  try {
   if (contextcompat.checkselfpermission(context, manifest.permission.record_audio) != packagemanager.permission_granted) {
    return false;
   } else {
    return true;
   }
  } catch (exception e) {
   return true;
  }

 }

 private static toast toast;

 /**
  * 单例吐司
  */
 public static void showtoast(context context, string msg) {
  if (toast == null) {
   toast = toast.maketext(context, msg, toast.length_short);
  }
  toast.settext(msg);
  toast.show();
 }

 /**
  * 获取指定文件夹下的所有文件路径
  *
  * @param root 指定文件夹路径
  * @return 指定文件夹下的所有文件
  */
 public static arraylist<string> getvideofiles(string root) {
  if (root == null || root == "")
   return null;

  arraylist<string> list = new arraylist<>();
  file file = new file(root);
  file[] filelist = file.listfiles();

  for (file f : filelist) {
   list.add(f.getpath());
  }

  return list;
 }

 /**
  * 获取声音文件名字
  *
  * @return 假如当前录制声音时间是2016年4月29号14点30分30秒。得到的文件名字就是20160429143030.这样保证文件名的唯一性
  */
 public static string getvoicefilename() {
  long getnowtimelong = system.currenttimemillis();
  simpledateformat time = new simpledateformat("yyyymmddhhmmss");
  string result = time.format(getnowtimelong);
  return result;
 }


}

5、mainactivity

package com.chen.voicedemo;

import android.app.activity;
import android.graphics.drawable.animationdrawable;
import android.graphics.drawable.colordrawable;
import android.media.mediaplayer;
import android.os.bundle;
import android.os.systemclock;
import android.util.log;
import android.view.layoutinflater;
import android.view.motionevent;
import android.view.view;
import android.view.viewgroup;
import android.view.window;
import android.view.windowmanager;
import android.widget.adapterview;
import android.widget.baseadapter;
import android.widget.imageview;
import android.widget.listview;
import android.widget.popupwindow;
import android.widget.textview;

import java.io.file;
import java.util.arraylist;
import java.util.list;

public class mainactivity extends activity implements view.ontouchlistener, adapterview.onitemclicklistener {

 /**
  * 开始录音按钮
  */
 private textview voice;
 /**
  * 用于定位。使录音时展示的popupwindow,展示在该控件 的下面
  */
 private textview voice_popup;

 /**
  * 展示指定文件夹下所有录制的声音文件
  */
 private textview show_voice_list;

 /**
  * 展示目标文件夹下,所有已录制的声音路径
  */
 private listview show_voices_listview;

 private list<string> voicelist;

 /**
  * 停止播放声音
  */
 private textview stop_show_voice;

 /**
  * 播放声音时,动的图片
  */
 private imageview voice_anim;

 /**
  * 系统播放器
  */
 private mediaplayer mediaplayer;

 private boolean flag = true;
 private float int_x = 0;
 private float int_y = 0;

 /**
  * 用于限制最大录音时常。单位是秒。意义是:最大录60秒的音频,到了60秒的是,自动停止
  */
 private int maxrecordtime = 60;

 /**
  * 用于显示频繁操作时间间隔。单位是毫秒。意义是:500毫秒内再次操作,就算是频频操作,做相应处理
  */
 private int oftenoperationtime = 500;

 private myadapter myadapter;

 private animationdrawable animation;

 /**
  * 录音popup
  */
 private popupwindow voice_popupwindow;
 /**
  * 录音时声音变化
  */
 private imageview voice_shengyin;
 /**
  * 录音计时器
  */
 private mychronometer mychronometer;

 @override
 protected void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);
  requestwindowfeature(window.feature_no_title);
  setcontentview(r.layout.activity_main);

  voicelist = new arraylist<string>();

  voice = (textview) findviewbyid(r.id.voice);
  voice_popup = (textview) findviewbyid(r.id.voice_popup);
  voice_anim = (imageview) findviewbyid(r.id.voice_anim);
  voice_anim.setimageresource(r.drawable.lcs_voice_receive);

  show_voice_list = (textview) findviewbyid(r.id.show_voice_list);

  show_voice_list.setonclicklistener(new view.onclicklistener() {
   @override
   public void onclick(view v) {
    voicelist = utils.getvideofiles(utils.image_sdcard_mader);
    if (voicelist.size()>0){
     myadapter.notifydatasetchanged();
    }else{
     utils.showtoast(mainactivity.this, "没有文件");
    }
   }
  });

  show_voices_listview = (listview) findviewbyid(r.id.show_voices);
  show_voices_listview.setonitemclicklistener(this);
  myadapter = new myadapter();

  stop_show_voice = (textview) findviewbyid(r.id.stop_show_voice);

  /**
   * 停止播放的监听器
   */
  stop_show_voice.setonclicklistener(new view.onclicklistener() {
   @override
   public void onclick(view v) {

    log.e("chen", "点击了停止播放按钮");

    if (mediaplayer != null) {
     if (mediaplayer.isplaying()) {
      mediaplayer.release();// 释放资源
     }
     mediaplayer = null;
    }
    if (animation != null && animation.isrunning()) {
     animation.stop();
    }
    voice_anim.setimageresource(r.drawable.lcs_voice_receive);
   }
  });

  show_voices_listview.setadapter(myadapter);

  voice.setontouchlistener(this);

 }

 /**
  * 声音文件列表的item点击事件,播放对应声音文件
  *
  * @param parent
  * @param view
  * @param position
  * @param id
  */
 @override
 public void onitemclick(adapterview<?> parent, view view, int position, long id) {

  //todo 以下4行,是用来做测试,点击item,手机sd卡上对应路径下的声音文件就会被删除。如果录制声音失败,或者不满足条件,可以把以下4行写成一个工具方法调用,删除不满意的文件。这里不做详细演示
  //file f_delete=new file(voicelist.get(position));
  //f_delete.delete();
  //voicelist.remove(voicelist.get(position));
  //myadapter.notifydatasetchanged();
  //todo 以上4行,是用来做测试,点击item,手机sd卡上对应路径下的声音文件就会被删除。

  try {
   mediaplayer = new mediaplayer();

   /**
    * 播放过程中展示的动画
    */
   mediaplayer.setonpreparedlistener(new mediaplayer.onpreparedlistener() {

    @override
    public void onprepared(mediaplayer mp) {
     if (mp != null) {
      mp.start();
      voice_anim.setimageresource(r.drawable.voice_anim);
     }
    }
   });

   /**
    * 播放完成监听
    */
   mediaplayer.setoncompletionlistener(new mediaplayer.oncompletionlistener() {
    @override
    public void oncompletion(mediaplayer mp) {
     if (mp.isplaying()) {
      mp.release();// 释放资源
     }
     animation = (animationdrawable) voice_anim.getdrawable();
     if (animation != null && animation.isrunning()) {
      animation.stop();
     }
     voice_anim.setimageresource(r.drawable.lcs_voice_receive);
    }
   });
   mediaplayer.setdatasource(voicelist.get(position));
   // 缓冲
   mediaplayer.prepare();

  } catch (exception e) {
   utils.showtoast(mainactivity.this, "语音异常,加载失败");
  }
 }

 /**
  * 展示声音列表的adapter
  */
 class myadapter extends baseadapter {

  @override
  public int getcount() {
   return voicelist.size() == 0 ? 0 : voicelist.size();
  }

  @override
  public object getitem(int position) {
   return null;
  }

  @override
  public long getitemid(int position) {
   return 0;
  }

  @override
  public view getview(int position, view convertview, viewgroup parent) {
   textview tv = new textview(mainactivity.this);
   tv.settext(voicelist.get(position));
   tv.settextsize(20);
   return tv;
  }
 }


 /**
  * 开始录制按钮的ontouch事件
  *
  * @param v
  * @param event
  * @return
  */
 @override
 public boolean ontouch(view v, motionevent event) {

  if (v.getid() == r.id.voice) {

   //检查权限
   if (!utils.checkvoice(this)) {
    if (event.getaction() == motionevent.action_down) {
     utils.showtoast(this, "录音权限未打开,请打开录音权限!");
    }
    return true;
   }

   //避免短时间里频繁操作
   if (!gettimetf(systemclock.elapsedrealtime()) && event.getaction() == motionevent.action_down) {
    utils.showtoast(this, "操作过于频繁");
    return true;
   }

   if (event.getaction() == motionevent.action_down) {
    settime(systemclock.elapsedrealtime());
   }
   switch (event.getaction()) {
    case motionevent.action_down:
     int_x = event.getrawx();
     int_y = event.getrawy();
     voicepopupwindow();
     mychronometer.setbase(systemclock.elapsedrealtime());
     mychronometer.start();
     mediarecorderutils.getinstence(voice_shengyin).mediarecorderstart();
     flag = true;
     mychronometer.setonmychronometerticklistener(new mychronometer.onmychronometerticklistener() {
      @override
      public void onmychronometertick(int time) {
       if (time == maxrecordtime || time > maxrecordtime) {
        mychronometer.settext("60");
        setvoicetoup();
       }
      }
     });
     break;
    case motionevent.action_move:
     if (flag) {
      if (math.abs(int_y) - math.abs(event.getrawy()) > 100.0 && flag) {
       voice_popupwindow.dismiss();
       mychronometer.stop();
       mediarecorderutils.getinstence(voice_shengyin).mediarecorderstop();
       mediarecorderutils.getinstence(voice_shengyin).mediarecorderdelete();
       flag = false;
      }
     }
     break;
    case motionevent.action_cancel:
     if (flag) {
      voice_popupwindow.dismiss();
      mychronometer.stop();
      mediarecorderutils.getinstence(voice_shengyin).mediarecorderstop();
     }
     break;
    case motionevent.action_up:
     if (flag) {
      setvoicetoup();
     }
     break;
   }
   return true;
  }
  return false;
 }

 private long base_time = 0;

 private void settime(long time) {
  base_time = time;
 }

 private boolean gettimetf(long time) {
  int data = (int) (time - base_time) / oftenoperationtime;
  if (data > 1) {
   return true;
  } else {
   return false;
  }
 }


 /**
  * 声音popupwindow
  */
 public void voicepopupwindow() {
  view view = layoutinflater.from(this).inflate(r.layout.voice_popupwindow, null);
  voice_popupwindow = new popupwindow(this);
  voice_popupwindow.setwidth(windowmanager.layoutparams.match_parent);
  voice_popupwindow.setheight(windowmanager.layoutparams.match_parent);
  voice_shengyin = (imageview) view.findviewbyid(r.id.voice_shengyin);
  mychronometer = (mychronometer) view.findviewbyid(r.id.mychronometer);
  voice_popupwindow.setcontentview(view);
  voice_popupwindow.setfocusable(true);
  colordrawable dw = new colordrawable(0x00000000);
  voice_popupwindow.setbackgrounddrawable(dw);
  voice_popupwindow.showasdropdown(voice_popup);
 }


 private void setvoicetoup() {
  flag = false;
  voice_popupwindow.dismiss();
  mychronometer.stop();
  mediarecorderutils.getinstence(voice_shengyin).mediarecorderstop();
  int time = integer.parseint(mychronometer.gettext().tostring());

  if (time != 0) {
   file file = new file(mediarecorderutils.getinstence(voice_shengyin).getpath());
   if (file.length() > 0) {
    voicelist = utils.getvideofiles(utils.image_sdcard_mader);
    myadapter.notifydatasetchanged();

   } else {
    utils.showtoast(this, "录音失败,请检查权限");
   }
  } else {
   utils.showtoast(this, "录音时间太短");
  }
 }

}

6、activity_main布局

<?xml version="1.0" encoding="utf-8"?>
<linearlayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical"
 >

 <textview
  android:id="@+id/voice_popup"
  android:layout_width="match_parent"
  android:layout_height="1dip"/>

 <listview
  android:id="@+id/show_voices"
  android:layout_width="match_parent"
  android:layout_height="0dp"
  android:layout_weight="1"/>


 <relativelayout
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:orientation="horizontal">

  <imageview
   android:id="@+id/voice_anim"
   android:layout_width="60dp"
   android:layout_height="30dp"
   android:layout_centervertical="true"
   android:layout_marginleft="30dp"
   android:background="#00ff00"/>


  <textview
   android:id="@+id/stop_show_voice"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_alignparentright="true"
   android:layout_centervertical="true"
   android:layout_gravity="center_horizontal"
   android:layout_marginbottom="20dp"
   android:layout_marginright="20dp"
   android:background="#00ff00"
   android:padding="10dp"
   android:text="停止播放"
   android:textcolor="#000000"
   android:textsize="20sp"
   />

  <textview
   android:id="@+id/show_voice_list"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_centervertical="true"
   android:layout_gravity="center_horizontal"
   android:layout_marginbottom="20dp"
   android:layout_marginright="20dp"
   android:layout_toleftof="@id/stop_show_voice"
   android:background="#00ff00"
   android:padding="10dp"
   android:text="列表"
   android:textcolor="#000000"
   android:textsize="20sp"
   />

 </relativelayout>

 <textview
  android:id="@+id/voice"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_gravity="center_horizontal"
  android:background="#00ff00"
  android:padding="10dp"
  android:text="开始录音"
  android:textcolor="#000000"
  android:textsize="25sp"/>
</linearlayout>

7、voice_popupwindow布局代码:录音的时候,会出现以下图片中的popupwindow

Android录制声音文件(音频)并播放

<?xml version="1.0" encoding="utf-8"?>
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

 <linearlayout
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_centerinparent="true"
  android:background="@android:color/black"
  android:orientation="vertical"
  android:paddingbottom="40dip"
  android:paddingleft="60dip"
  android:paddingright="60dip"
  android:paddingtop="40dip">

  <imageview
   android:id="@+id/voice_shengyin"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_gravity="center_horizontal"
   android:src="@drawable/rc_ic_volume_1"/>

  <com.chen.voicedemo.mychronometer
   android:id="@+id/mychronometer"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_centerhorizontal="true"
   android:layout_gravity="center_horizontal"
   android:textcolor="@android:color/white"/>

 </linearlayout>
</relativelayout>

8、还有一个动画布局,播放声音的时候,有个动画效果

Android录制声音文件(音频)并播放

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/volume_animation"
    android:oneshot="false" >

 <item
  android:drawable="@drawable/rc_ic_voice_receive_play1"
  android:duration="100"/>
 <item
  android:drawable="@drawable/rc_ic_voice_receive_play2"
  android:duration="200"/>
 <item
  android:drawable="@drawable/rc_ic_voice_receive_play3"
  android:duration="300"/>

</animation-list>

附录:用到的图片资源说明:如果手上没有这样的图片,可以随便用其他图片代替,有效果,就算成功

Android录制声音文件(音频)并播放

Android录制声音文件(音频)并播放

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