温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

如何使用Android仿微信语音对讲录音功能

发布时间:2021-09-27 11:42:51 来源:亿速云 阅读:145 作者:小新 栏目:编程语言

这篇文章主要介绍如何使用Android仿微信语音对讲录音功能,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

实现思路:

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, 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仿微信语音对讲录音功能”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注亿速云行业资讯频道!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI