千家信息网

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

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,这篇文章主要介绍如何使用Android仿微信语音对讲录音功能,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!实现思路:1.在微信中我们可以看到实现语音对讲的是通过点按按钮来完成的
千家信息网最后更新 2026年10月31日如何使用Android仿微信语音对讲录音功能

这篇文章主要介绍如何使用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添加权限:

代码参考

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布局:

录音时间太短的Toast布局:

自定义的Dialogstyle,对话框样式

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

手指 时间 方法 音量 文件 策略 大小 线程 语音 对讲 不同 图片 对话框 按钮 接口 音频 对话 移动 功能 内容 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 瑰夏咖啡 互联网科技工作委员会副主任毛军 善班互联网科技有限公司 顺玮阁互联网科技 互联网科技公司介绍 四川狮子座互联网科技 互联网汽车科技小镇 广州优美互联网科技 厦门比较好的科技互联网公司 互联网公司科技股 中国互联网十大科技股排名 阿里互联网科技企业 中和天地互联网科技有限公司 厦门江牛科技互联网 江苏互联网科技小贷 工业互联网科技创业 西安有哪些互联网高科技企业 马化腾互联网科技教学 数字科技和互联网金融哪个好 瑞安市蟠桃会互联网科技有限公司 科技金融是不是互联网金融 厦门中拓互联网络科技有限公司 互联网科技股有哪些 广州优美互联网科技 电子科技大学互联网创业大赛 西安小鹰速贷互联网科技有限公司 深圳市罗太互联网科技有限公司 广州燕处互联网科技有限公司 互联网金融金融科技 恒生互联网科技趋势
0