Android仿微信语音对讲录音功能

Android仿微信语音对讲录音功能,第1张

概述Android仿微信语音对讲录音功能 自微信出现以来取得了很好的成绩,语音对讲的实现更加方便了人与人之间的交流.今天来实践一下微信的语音对讲的录音实现,这个也比较容易实现.在此,我将该按钮封装成为一个控件,并通过策略模式的方式实现录音和界面的解耦合,以方便我们在实际情况中对录音方法的不同需求(例如想要实现wav格式的编码时我们也就不能再使用MediaRecorder,而只能使用AudioRecord进行处理). 效果图: 实现思路: 1.在微信中我们可以看到实现语音对讲的是通过点按按钮来完成的,因此在这里我选择重新自己的控件使其继承

自微信出现以来取得了很好的成绩,语音对讲的实现更加方便了人与人之间的交流。今天来实践一下微信的语音对讲的录音实现,这个也比较容易实现。在此,我将该按钮封装成为一个控件,并通过策略模式的方式实现录音和界面的解耦合,以方便我们在实际情况中对录音方法的不同需求(例如想要实现wav格式的编码时我们也就不能再使用MediaRecorder,而只能使用AudioRecord进行处理)。

效果图:


实现思路:

1.在微信中我们可以看到实现语音对讲的是通过点按按钮来完成的,因此在这里我选择重新自己的控件使其继承自button并重写ontouchEvent方法,来实现对录音的判断。

2.在ontouchEvent方法中,

当我们按下按钮时,首先显示录音的对话框,然后调用录音准备方法并开始录音,接着开启一个计时线程,每隔0.1秒的时间获取一次录音音量的大小,并通过Handler根据音量大小更新Dialog中的显示图片;

当我们移动手指时,若手指向上移动距离大于50,在Dialog中显示松开手指取消录音的提示,并将isCanceled变量(表示我们最后是否取消了录音)置为true,上移动距离小于20时,我们恢复Dialog的图片,并将isCanceled置为false;
当抬起手指时,我们首先关闭录音对话框,接着调用录音停止方法并关闭计时线程,然后我们判断是否取消录音,若是的话则删除录音文件,否则判断计时时间是否太短,最后调用回调接口中的recordEnd方法。

3.在这里为了适应不同的录音需求,我使用了策略模式来进行处理,将每一个不同的录音方法视为一种不同的策略,根据自己的需要去改写。

注意问题

1.在ontouchEvent的返回值中应该返回true,这样才能屏蔽之后其他的触摸事件,否则当手指滑动离开button之后将不能在响应我们的触摸方法。
2.不要忘记为自己的App添加权限:

<uses-permission androID:name="androID.permission.RECORD_AUdio" /><uses-permission androID:name="androID.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission androID:name="androID.permission.READ_EXTERNAL_STORAGE" />

代码参考

Recordbutton 类,我们的自定义控件,重新复写了ontouchEvent方法

package com.example.recordtest;import androID.annotation.Suppresslint;import androID.app.Dialog;import androID.content.Context;import androID.os.Handler;import androID.os.Message;import androID.util.AttributeSet;import androID.vIEw.Gravity;import androID.vIEw.LayoutInflater;import androID.vIEw.MotionEvent;import androID.vIEw.VIEw;import androID.Widget.button;import androID.Widget.ImageVIEw;import androID.Widget.TextVIEw;import androID.Widget.Toast;public class Recordbutton extends button {  private static final int MIN_RECORD_TIME = 1; // 最短录音时间,单位秒  private static final int RECORD_OFF = 0; // 不在录音  private static final int RECORD_ON = 1; // 正在录音  private Dialog mRecordDialog;  private RecordStrategy mAudioRecorder;  private Thread mRecordThread;  private RecordListener Listener;  private int recordState = 0; // 录音状态  private float recodeTime = 0.0f; // 录音时长,如果录音时间太短则录音失败  private double voiceValue = 0.0; // 录音的音量值  private boolean isCanceled = false; // 是否取消录音  private float downY;  private TextVIEw dialogTextVIEw;  private ImageVIEw dialogimg;  private Context mContext;  public Recordbutton(Context context) {    super(context);    // Todo auto-generated constructor stub    init(context);  }  public Recordbutton(Context context,AttributeSet attrs,int defStyle) {    super(context,attrs,defStyle);    // Todo auto-generated constructor stub    init(context);  }  public Recordbutton(Context context,AttributeSet attrs) {    super(context,attrs);    // Todo auto-generated constructor stub    init(context);  }  private voID init(Context context) {    mContext = context;    this.setText("按住 说话");  }  public voID setAudioRecord(RecordStrategy record) {    this.mAudioRecorder = record;  }  public voID setRecordListener(RecordListener Listener) {    this.Listener = Listener;  }  // 录音时显示Dialog  private voID showVoiceDialog(int flag) {    if (mRecordDialog == null) {      mRecordDialog = new Dialog(mContext,R.style.Dialogstyle);      mRecordDialog.setContentVIEw(R.layout.dialog_record);      dialogimg = (ImageVIEw) mRecordDialog          .findVIEwByID(R.ID.record_dialog_img);      dialogTextVIEw = (TextVIEw) mRecordDialog          .findVIEwByID(R.ID.record_dialog_txt);    }    switch (flag) {    case 1:      dialogimg.setimageResource(R.drawable.record_cancel);      dialogTextVIEw.setText("松开手指可取消录音");      this.setText("松开手指 取消录音");      break;    default:      dialogimg.setimageResource(R.drawable.record_animate_01);      dialogTextVIEw.setText("向上滑动可取消录音");      this.setText("松开手指 完成录音");      break;    }    dialogTextVIEw.setTextSize(14);    mRecordDialog.show();  }  // 录音时间太短时Toast显示  private voID showWarnToast(String toastText) {    Toast toast = new Toast(mContext);    VIEw warnVIEw = LayoutInflater.from(mContext).inflate(        R.layout.toast_warn,null);    toast.setVIEw(warnVIEw);    toast.setGravity(Gravity.CENTER,0);// 起点位置为中间    toast.show();  }  // 开启录音计时线程  private voID callrecordTimeThread() {    mRecordThread = new Thread(recordThread);    mRecordThread.start();  }  // 录音Dialog图片随录音音量大小切换  private voID setDialogImage() {    if (voiceValue < 600.0) {      dialogimg.setimageResource(R.drawable.record_animate_01);    } else if (voiceValue > 600.0 && voiceValue < 1000.0) {      dialogimg.setimageResource(R.drawable.record_animate_02);    } else if (voiceValue > 1000.0 && voiceValue < 1200.0) {      dialogimg.setimageResource(R.drawable.record_animate_03);    } else if (voiceValue > 1200.0 && voiceValue < 1400.0) {      dialogimg.setimageResource(R.drawable.record_animate_04);    } else if (voiceValue > 1400.0 && voiceValue < 1600.0) {      dialogimg.setimageResource(R.drawable.record_animate_05);    } else if (voiceValue > 1600.0 && voiceValue < 1800.0) {      dialogimg.setimageResource(R.drawable.record_animate_06);    } else if (voiceValue > 1800.0 && voiceValue < 2000.0) {      dialogimg.setimageResource(R.drawable.record_animate_07);    } else if (voiceValue > 2000.0 && voiceValue < 3000.0) {      dialogimg.setimageResource(R.drawable.record_animate_08);    } else if (voiceValue > 3000.0 && voiceValue < 4000.0) {      dialogimg.setimageResource(R.drawable.record_animate_09);    } else if (voiceValue > 4000.0 && voiceValue < 6000.0) {      dialogimg.setimageResource(R.drawable.record_animate_10);    } else if (voiceValue > 6000.0 && voiceValue < 8000.0) {      dialogimg.setimageResource(R.drawable.record_animate_11);    } else if (voiceValue > 8000.0 && voiceValue < 10000.0) {      dialogimg.setimageResource(R.drawable.record_animate_12);    } else if (voiceValue > 10000.0 && voiceValue < 12000.0) {      dialogimg.setimageResource(R.drawable.record_animate_13);    } else if (voiceValue > 12000.0) {      dialogimg.setimageResource(R.drawable.record_animate_14);    }  }  // 录音线程  private Runnable recordThread = new Runnable() {    @OverrIDe    public voID run() {      recodeTime = 0.0f;      while (recordState == RECORD_ON) {        {          try {            Thread.sleep(100);            recodeTime += 0.1;            // 获取音量,更新dialog            if (!isCanceled) {              voiceValue = mAudioRecorder.getAmplitude();              recordHandler.sendEmptyMessage(1);            }          } catch (InterruptedException e) {            e.printstacktrace();          }        }      }    }  };  @Suppresslint("HandlerLeak")  private Handler recordHandler = new Handler() {    @OverrIDe    public voID handleMessage(Message msg) {      setDialogImage();    }  };  @OverrIDe  public boolean ontouchEvent(MotionEvent event) {    // Todo auto-generated method stub    switch (event.getAction()) {    case MotionEvent.ACTION_DOWN: // 按下按钮      if (recordState != RECORD_ON) {        showVoiceDialog(0);        downY = event.getY();        if (mAudioRecorder != null) {          mAudioRecorder.ready();          recordState = RECORD_ON;          mAudioRecorder.start();          callrecordTimeThread();        }      }      break;    case MotionEvent.ACTION_MOVE: // 滑动手指      float moveY = event.getY();      if (downY - moveY > 50) {        isCanceled = true;        showVoiceDialog(1);      }      if (downY - moveY < 20) {        isCanceled = false;        showVoiceDialog(0);      }      break;    case MotionEvent.ACTION_UP: // 松开手指      if (recordState == RECORD_ON) {        recordState = RECORD_OFF;        if (mRecordDialog.isShowing()) {          mRecordDialog.dismiss();        }        mAudioRecorder.stop();        mRecordThread.interrupt();        voiceValue = 0.0;        if (isCanceled) {          mAudioRecorder.deleteoldfile();        } else {          if (recodeTime < MIN_RECORD_TIME) {            showWarnToast("时间太短 录音失败");            mAudioRecorder.deleteoldfile();          } else {            if (Listener != null) {              Listener.recordEnd(mAudioRecorder.getfilePath());            }          }        }        isCanceled = false;        this.setText("按住 说话");      }      break;    }    return true;  }  public interface RecordListener {    public voID recordEnd(String filePath);  }}

Dialog布局:

<?xml version="1.0" enCoding="utf-8"?><linearLayout xmlns:androID="http://schemas.androID.com/apk/res/androID"  androID:orIEntation="vertical"  androID:layout_wIDth="wrap_content"  androID:layout_height="wrap_content"  androID:layout_gravity="center"  androID:gravity="center"  androID:background="@drawable/record_bg"  androID:padding="20dp" >  <ImageVIEw    androID:ID="@+ID/record_dialog_img"    androID:layout_wIDth="wrap_content"    androID:layout_height="wrap_content" />  <TextVIEw    androID:ID="@+ID/record_dialog_txt"    androID:layout_wIDth="wrap_content"    androID:layout_height="wrap_content"    androID:textcolor="@androID:color/white"    androID:layout_margintop="5dp" /></linearLayout>

录音时间太短的Toast布局:

<?xml version="1.0" enCoding="utf-8"?><linearLayout xmlns:androID="http://schemas.androID.com/apk/res/androID"  androID:layout_wIDth="wrap_content"  androID:layout_height="wrap_content"  androID:background="@drawable/record_bg"  androID:padding="20dp"  androID:gravity="center"  androID:orIEntation="vertical" >  <ImageVIEw    androID:layout_wIDth="wrap_content"    androID:layout_height="wrap_content"    androID:src="@drawable/voice_to_short" />  <TextVIEw    androID:layout_wIDth="wrap_content"    androID:layout_height="wrap_content"    androID:textcolor="@androID:color/white"    androID:textSize="15sp"    androID:text="时间太短 录音失败" /></linearLayout>

自定义的Dialogstyle,对话框样式

<style name="Dialogstyle">    <item name="androID:windowBackground">@androID:color/transparent</item>    <item name="androID:windowFrame">@null</item>    <item name="androID:windowNoTitle">true</item>    <item name="androID:windowIsfloating">true</item>    <item name="androID:windowIsTranslucent">true</item>    <item name="androID:windowAnimationStyle">@androID:style/Animation.Dialog</item>    <!-- 显示对话框时当前的屏幕是否变暗 -->    <item name="androID:backgroundDimEnabled">false</item></style>

RecordStrategy 录音策略接口

package com.example.recordtest;/** * RecordStrategy 录音策略接口 * @author acer */public interface RecordStrategy {  /**   * 在这里进行录音准备工作,重置录音文件名等   */  public voID ready();  /**   * 开始录音   */  public voID start();  /**   * 录音结束   */  public voID stop();  /**   * 录音失败时删除原来的旧文件   */  public voID deleteoldfile();  /**   * 获取录音音量的大小   * @return   */  public double getAmplitude();  /**   * 返回录音文件完整路径   * @return   */  public String getfilePath();}

个人写的一个录音实践策略

package com.example.recordtest;import java.io.file;import java.io.IOException;import java.text.SimpleDateFormat;import java.util.Date;import androID.media.MediaRecorder;import androID.os.Environment;public class AudioRecorder implements RecordStrategy {  private MediaRecorder recorder;  private String filename;  private String fileFolder = Environment.getExternalStorageDirectory()      .getPath() + "/TestRecord";  private boolean isRecording = false;  @OverrIDe  public voID ready() {    // Todo auto-generated method stub    file file = new file(fileFolder);    if (!file.exists()) {      file.mkdir();    }    filename = getCurrentDate();    recorder = new MediaRecorder();    recorder.setoutputfile(fileFolder + "/" + filename + ".amr");    recorder.setAudioSource(MediaRecorder.AudioSource.MIC);// 设置MediaRecorder的音频源为麦克风    recorder.setoutputFormat(MediaRecorder.OutputFormat.RAW_AMR);// 设置MediaRecorder录制的音频格式    recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);// 设置MediaRecorder录制音频的编码为amr  }  // 以当前时间作为文件名  private String getCurrentDate() {    SimpleDateFormat formatter = new SimpleDateFormat("yyyy_MM_dd_HHmmss");    Date curDate = new Date(System.currentTimeMillis());// 获取当前时间    String str = formatter.format(curDate);    return str;  }  @OverrIDe  public voID start() {    // Todo auto-generated method stub    if (!isRecording) {      try {        recorder.prepare();        recorder.start();      } catch (IllegalStateException e) {        // Todo auto-generated catch block        e.printstacktrace();      } catch (IOException e) {        // Todo auto-generated catch block        e.printstacktrace();      }      isRecording = true;    }  }  @OverrIDe  public voID stop() {    // Todo auto-generated method stub    if (isRecording) {      recorder.stop();      recorder.release();      isRecording = false;    }  }  @OverrIDe  public voID deleteoldfile() {    // Todo auto-generated method stub    file file = new file(fileFolder + "/" + filename + ".amr");    file.deleteOnExit();  }  @OverrIDe  public double getAmplitude() {    // Todo auto-generated method stub    if (!isRecording) {      return 0;    }    return recorder.getMaxAmplitude();  }  @OverrIDe  public String getfilePath() {    // Todo auto-generated method stub    return fileFolder + "/" + filename + ".amr";  }}

MainActivity

package com.example.recordtest;import androID.os.Bundle;import androID.app.Activity;import androID.vIEw.Menu;public class MainActivity extends Activity {  Recordbutton button;  @OverrIDe  protected voID onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentVIEw(R.layout.activity_main);    button = (Recordbutton) findVIEwByID(R.ID.btn_record);    button.setAudioRecord(new AudioRecorder());  }  @OverrIDe  public boolean onCreateOptionsMenu(Menu menu) {    // Inflate the menu; this adds items to the action bar if it is present.    getMenuInflater().inflate(R.menu.main,menu);    return true;  }}

源码下载:AndroID仿微信语音对讲录音

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

总结

以上是内存溢出为你收集整理的Android仿微信语音对讲录音功能全部内容,希望文章能够帮你解决Android仿微信语音对讲录音功能所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1144329.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存