提要:需求是开发类似微信发语音的功能,没有语音转文字。网上看了一些代码,不能拿来直接用,部分代码逻辑有问题,所以想把自己的代码贴出来,仅供参考。

功能:

a、设置最大录音时长和录音倒计时(为了方便测试,最大时长设置为15秒,开始倒计时设置为7秒)

b、在录音之前检查录音和存储权限

源码:

1、录音对话框管理类DialogManager:

/**

* 功能:录音对话框管理类

*/

public class DialogManager {

private AlertDialog.Builder builder;

private AlertDialog dialog;

private ImageView mIcon;

private ImageView mVoice;

private TextView mLabel;

private Context context;

/**

* 构造方法

*

* @param context Activity级别的Context

*/

public DialogManager(Context context) {

this.context = context;

}

/**

* 显示录音的对话框

*/

public void showRecordingDialog() {

builder = new AlertDialog.Builder(context, R.style.AudioRecorderDialogStyle);

LayoutInflater inflater = LayoutInflater.from(context);

View view = inflater.inflate(R.layout.audio_recorder_dialog, null);

mIcon = view.findViewById(R.id.iv_dialog_icon);

mVoice = view.findViewById(R.id.iv_dialog_voice);

mLabel = view.findViewById(R.id.tv_dialog_label);

builder.setView(view);

dialog = builder.create();

dialog.show();

dialog.setCanceledOnTouchOutside(false);

}

/**

* 正在播放时的状态

*/

public void recording() {

if (dialog != null && dialog.isShowing()) { //显示状态

mIcon.setVisibility(View.VISIBLE);

mVoice.setVisibility(View.VISIBLE);

mLabel.setVisibility(View.VISIBLE);

mIcon.setImageResource(R.drawable.ic_audio_recorder);

mVoice.setImageResource(R.drawable.ic_audio_v1);

mLabel.setText(R.string.audio_record_dialog_up_to_cancel);

}

}

/**

* 显示想取消的对话框

*/

public void wantToCancel() {

if (dialog != null && dialog.isShowing()) { //显示状态

mIcon.setVisibility(View.VISIBLE);

mVoice.setVisibility(View.GONE);

mLabel.setVisibility(View.VISIBLE);

mIcon.setImageResource(R.drawable.ic_audio_cancel);

mLabel.setText(R.string.audio_record_dialog_release_to_cancel);

}

}

/**

* 显示时间过短的对话框

*/

public void tooShort() {

if (dialog != null && dialog.isShowing()) { //显示状态

mIcon.setVisibility(View.VISIBLE);

mVoice.setVisibility(View.GONE);

mLabel.setVisibility(View.VISIBLE);

mLabel.setText(R.string.audio_record_dialog_too_short);

}

}

// 显示取消的对话框

public void dismissDialog() {

if (dialog != null && dialog.isShowing()) { //显示状态

dialog.dismiss();

dialog = null;

}

}

/**

* 显示更新音量级别的对话框

*

* @param level 1-7

*/

public void updateVoiceLevel(int level) {

if (dialog != null && dialog.isShowing()) { //显示状态

mIcon.setVisibility(View.VISIBLE);

mVoice.setVisibility(View.VISIBLE);

mLabel.setVisibility(View.VISIBLE);

int resId = context.getResources().getIdentifier("ic_audio_v" + level, "drawable", context.getPackageName());

mVoice.setImageResource(resId);

}

}

public void updateTime(int time) {

if (dialog != null && dialog.isShowing()) { //显示状态

mIcon.setVisibility(View.VISIBLE);

mVoice.setVisibility(View.VISIBLE);

mLabel.setVisibility(View.VISIBLE);

mLabel.setText(time + "s");

}

}

}

2、录音管理类AudioManager

/**

* 功能:录音管理类

*/

public class AudioManager {

private MediaRecorder mMediaRecorder;

private String mDir;

private String mCurrentFilePath;

private static AudioManager mInstance;

private boolean isPrepared;

private AudioManager(String dir) {

this.mDir = dir;

}

//单例模式:在这里实例化AudioManager并传入录音文件地址

public static AudioManager getInstance(String dir) {

if (mInstance == null) {

synchronized (AudioManager.class) {

if (mInstance == null) {

mInstance = new AudioManager(dir);

}

}

}

return mInstance;

}

/**

* 回调准备完毕

*/

public interface AudioStateListener {

void wellPrepared();

}

public AudioStateListener mListener;

/**

* 回调方法

*/

public void setOnAudioStateListener(AudioStateListener listener) {

mListener = listener;

}

/**

* 准备

*/

public void prepareAudio() {

try {

isPrepared = false;

File dir = FileUtils.createNewFile(mDir);

String fileName = generateFileName();

File file = new File(dir, fileName);

mCurrentFilePath = file.getAbsolutePath();

Logger.t("AudioManager").i("audio file name :" + mCurrentFilePath);

mMediaRecorder = new MediaRecorder();

//设置输出文件

mMediaRecorder.setOutputFile(mCurrentFilePath);

//设置MediaRecorder的音频源为麦克风

mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);

//设置音频格式

mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);

//设置音频的格式为AAC

mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);

//准备录音

mMediaRecorder.prepare();

//开始

mMediaRecorder.start();

//准备结束

isPrepared = true;

if (mListener != null) {

mListener.wellPrepared();

}

} catch (Exception e) {

e.printStackTrace();

}

}

/**

* 随机生成文件的名称

*/

private String generateFileName() {

return UUID.randomUUID().toString() + ".m4a";

}

public int getVoiceLevel(int maxLevel) {

if (isPrepared) {

try {

//获得最大的振幅getMaxAmplitude() 1-32767

return maxLevel * mMediaRecorder.getMaxAmplitude() / 32768 + 1;

} catch (Exception e) {

}

}

return 1;

}

/**

* 释放资源

*/

public void release() {

if (mMediaRecorder != null) {

mMediaRecorder.stop();

mMediaRecorder.release();

mMediaRecorder = null;

}

}

public void cancel() {

release();

if (mCurrentFilePath != null) {

File file = new File(mCurrentFilePath);

FileUtils.deleteFile(file);

mCurrentFilePath = null;

}

}

public String getCurrentFilePath() {

return mCurrentFilePath;

}

}

3、自定义录音按钮AudioRecorderButton

/**

* 功能:录音按钮

*/

public class AudioRecorderButton extends AppCompatButton {

private Context mContext;

//取消录音Y轴位移

private static final int DISTANCE_Y_CANCEL = 80;

//录音最大时长限制

private static final int AUDIO_RECORDER_MAX_TIME = 15;

//录音倒计时时间

private static final int AUDIO_RECORDER_COUNT_DOWN = 7;

//状态

private static final int STATE_NORMAL = 1;// 默认的状态

private static final int STATE_RECORDING = 2;// 正在录音

private static final int STATE_WANT_TO_CANCEL = 3;// 希望取消

//当前的状态

private int mCurrentState = STATE_NORMAL;

//已经开始录音

private boolean isRecording = false;

//是否触发onLongClick

private boolean mReady;

private DialogManager mDialogManager;

private AudioManager mAudioManager;

private android.media.AudioManager audioManager;

public AudioRecorderButton(Context context) {

this(context, null);

}

public AudioRecorderButton(Context context, AttributeSet attrs) {

super(context, attrs);

this.mContext = context;

mDialogManager = new DialogManager(context);

audioManager = (android.media.AudioManager) context.getSystemService(Context.AUDIO_SERVICE);

String dir = SdUtils.getCustomFolder("Audios");//创建文件夹

mAudioManager = AudioManager.getInstance(dir);

mAudioManager.setOnAudioStateListener(new AudioManager.AudioStateListener() {

@Override

public void wellPrepared() {

mHandler.sendEmptyMessage(MSG_AUDIO_PREPARED);

}

});

//按钮长按 准备录音 包括start

setOnLongClickListener(new OnLongClickListener() {

@Override

public boolean onLongClick(View v) {

//先判断有没有录音和存储权限,有则开始录音,没有就申请权限

int hasAudioPermission = ContextCompat.checkSelfPermission(mContext, Manifest.permission.RECORD_AUDIO);

int hasStoragePermission = ContextCompat.checkSelfPermission(mContext, Manifest.permission.WRITE_EXTERNAL_STORAGE);

if (hasAudioPermission == PackageManager.PERMISSION_GRANTED && hasStoragePermission == PackageManager.PERMISSION_GRANTED) {

mReady = true;

mAudioManager.prepareAudio();

} else {

RxPermissions permissions = new RxPermissions((FragmentActivity) mContext);

Disposable disposable = permissions.request(Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE)

.subscribe(new Consumer() {

@Override

public void accept(Boolean granted) {

if (!granted) {

ToastUtils.showShort("发送语音功能需要赋予录音和存储权限");

}

}

});

}

return true;

}

});

}

private static final int MSG_AUDIO_PREPARED = 0X110;

private static final int MSG_VOICE_CHANGED = 0X111;

private static final int MSG_DIALOG_DISMISS = 0X112;

private static final int MSG_TIME_OUT = 0x113;

private static final int UPDATE_TIME = 0x114;

private boolean mThreadFlag = false;

//录音时长

private float mTime;

//获取音量大小的Runnable

private Runnable mGetVoiceLevelRunnable = new Runnable() {

@Override

public void run() {

while (isRecording) {

try {

Thread.sleep(100);

mTime += 0.1f;

mHandler.sendEmptyMessage(MSG_VOICE_CHANGED);

if (mTime >= AUDIO_RECORDER_MAX_TIME) {//如果时间超过60秒,自动结束录音

while (!mThreadFlag) {//记录已经结束了录音,不需要再次结束,以免出现问题

mDialogManager.dismissDialog();

mAudioManager.release();

if (audioFinishRecorderListener != null) {

//先回调,再Reset,不然回调中的时间是0

audioFinishRecorderListener.onFinish(mTime, mAudioManager.getCurrentFilePath());

mHandler.sendEmptyMessage(MSG_TIME_OUT);

}

mThreadFlag = !mThreadFlag;

}

isRecording = false;

} else if (mTime >= AUDIO_RECORDER_COUNT_DOWN) {

mHandler.sendEmptyMessage(UPDATE_TIME);

}

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

};

private Handler mHandler = new Handler(new Handler.Callback() {

@Override

public boolean handleMessage(Message msg) {

switch (msg.what) {

case MSG_AUDIO_PREPARED:

mDialogManager.showRecordingDialog();

isRecording = true;

new Thread(mGetVoiceLevelRunnable).start();

break;

case MSG_VOICE_CHANGED:

mDialogManager.updateVoiceLevel(mAudioManager.getVoiceLevel(7));

break;

case MSG_DIALOG_DISMISS:

mDialogManager.dismissDialog();

break;

case MSG_TIME_OUT:

reset();

break;

case UPDATE_TIME:

int countDown = (int) (AUDIO_RECORDER_MAX_TIME - mTime);

mDialogManager.updateTime(countDown);

break;

}

return true;

}

});

/**

* 录音完成后的回调

*/

public interface AudioFinishRecorderListener {

/**

* @param seconds 时长

* @param filePath 文件

*/

void onFinish(float seconds, String filePath);

}

private AudioFinishRecorderListener audioFinishRecorderListener;

public void setAudioFinishRecorderListener(AudioFinishRecorderListener listener) {

audioFinishRecorderListener = listener;

}

android.media.AudioManager.OnAudioFocusChangeListener onAudioFocusChangeListener = new android.media.AudioManager.OnAudioFocusChangeListener() {

@Override

public void onAudioFocusChange(int focusChange) {

if (focusChange == android.media.AudioManager.AUDIOFOCUS_LOSS) {

audioManager.abandonAudioFocus(onAudioFocusChangeListener);

}

}

};

public void myRequestAudioFocus() {

audioManager.requestAudioFocus(onAudioFocusChangeListener, android.media.AudioManager.STREAM_MUSIC, android.media.AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);

}

@Override

public boolean onTouchEvent(MotionEvent event) {

Logger.t("AudioManager").i("x :" + event.getX() + "-Y:" + event.getY());

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

mThreadFlag = false;

isRecording = true;

changeState(STATE_RECORDING);

myRequestAudioFocus();

break;

case MotionEvent.ACTION_MOVE:

if (isRecording) {

//根据想x,y的坐标,判断是否想要取消

if (event.getY() < 0 && Math.abs(event.getY()) > DISTANCE_Y_CANCEL) {

changeState(STATE_WANT_TO_CANCEL);

} else {

changeState(STATE_RECORDING);

}

}

break;

case MotionEvent.ACTION_UP:

//如果longClick 没触发

if (!mReady) {

reset();

return super.onTouchEvent(event);

}

//触发了onLongClick 没准备好,但是已经prepared已经start

//所以消除文件夹

if (!isRecording || mTime < 1.0f) {

mDialogManager.tooShort();

mAudioManager.cancel();

mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DISMISS, 1000);

} else if (mCurrentState == STATE_RECORDING) {//正常录制结束

mDialogManager.dismissDialog();

mAudioManager.release();

if (audioFinishRecorderListener != null) {

audioFinishRecorderListener.onFinish(mTime, mAudioManager.getCurrentFilePath());

}

} else if (mCurrentState == STATE_WANT_TO_CANCEL) {

mDialogManager.dismissDialog();

mAudioManager.cancel();

}

reset();

audioManager.abandonAudioFocus(onAudioFocusChangeListener);

break;

}

return super.onTouchEvent(event);

}

/**

* 恢复状态 标志位

*/

private void reset() {

isRecording = false;

mTime = 0;

mReady = false;

changeState(STATE_NORMAL);

}

/**

* 改变状态

*/

private void changeState(int state) {

if (mCurrentState != state) {

mCurrentState = state;

switch (state) {

case STATE_NORMAL:

setText(R.string.audio_record_button_normal);

break;

case STATE_RECORDING:

if (isRecording) {

mDialogManager.recording();

}

setText(R.string.audio_record_button_recording);

break;

case STATE_WANT_TO_CANCEL:

mDialogManager.wantToCancel();

setText(R.string.audio_record_button_cancel);

break;

}

}

}

}

4、DialogStyle

true

@style/ActivityAnimTheme

@style/MenuStyle

@android:color/transparent

true

@null

true

true

@style/ActivityDialogAnimation

false

@anim/fade_in

@anim/fade_out

5、DialogLayout

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:background="@drawable/audio_recorder_dialog_bg"

android:gravity="center"

android:orientation="vertical"

android:padding="20dp">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:orientation="horizontal">

android:id="@+id/iv_dialog_icon"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@drawable/ic_audio_recorder" />

android:id="@+id/iv_dialog_voice"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@drawable/ic_audio_v1" />

android:id="@+id/tv_dialog_label"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginTop="15dp"

android:text="@string/audio_record_dialog_up_to_cancel"

android:textColor="@color/white"

android:textSize="15dp" />

6、用到的字符串

按住 说话

松开 结束

松开手指 取消发送

手指上划,取消发送

松开手指,取消发送

录音时间过短

7、使用:按钮的样式不需要写在自定义Button中,方便使用

android:id="@+id/btn_audio_recorder"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@string/audio_record_button_normal" />

AudioRecorderButton audioRecorderButton = findViewById(R.id.btn_audio_recorder);

audioRecorderButton.setAudioFinishRecorderListener(new AudioRecorderButton.AudioFinishRecorderListener() {

@Override

public void onFinish(float seconds, String filePath) {

Logger.i(seconds + "秒:" + filePath);

}

});

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

android按住录音按钮_Android仿微信录音功能相关推荐

  1. android按住录音按钮_Android模仿微信录音、发送语音效果实现

    在项目开发中,有个需求:实现模仿微信录音,发送语音的功能.长按按钮录音,弹框显示语音时间,以及上滑取消发送.我重写了一个发送语音的控件,以实现该功能. 首先添加权限: AudioRecorderBut ...

  2. android按住录音按钮_Android实现录音方法(仿微信语音、麦克风录音、发送语音、解决5.0以上BUG)...

    先给大家展示下效果图,如果大家感觉不错,请参考使用方法, 效果图如下所示: 使用方法: 录音工具类:AudioRecoderUtils.java,代码如下: public class AudioRec ...

  3. android 录音的格式转换,Android仿微信录音功能(录音后的raw文件转mp3文件)

    现在很多时候需要用到录音,然后如果我们的App是ios和android两端的话,就要考虑录音的文件在两端都能使用,这个时候就需要适配,两端的录音文件都要是mp3文件,这样才能保证两边都能播放. 针对这 ...

  4. Android 二维码扫描(仿微信界面),根据Google zxing

    Android 二维码扫描(仿微信界面),根据Google zxing Android项目开发中经常会用到二维码扫描,例如登陆.支付等谷歌方面已经有了一个开源库(地址: https://github. ...

  5. Android 使用 CameraX 快速实现仿微信短视频录制

    Android 使用 CameraX 快速实现仿微信短视频录制(轻触拍照.长按录像) https://github.com/ldlywt/MyCameraX 微信短视频android端 https:/ ...

  6. Android仿微信录音功能,自定义控件的设计技巧

    欢迎各位加入我的Android开发群[257053751] 最近由于需要做一个录音功能(/嘘 悄悄透露一下,千万别告诉红薯,就是新版本的OSC客户端噢),起初打算采用仿微信的录音方式,最后又改成了QQ ...

  7. android 微信浮窗实现_Android仿微信视屏悬浮窗效果

    在项目中需要对接入的腾讯云音视频,可以悬浮窗显示,悬浮窗可拖拽,并且在悬浮窗不影响其他的activity的焦点. 这个大神的文章Android基于腾讯云实时音视频仿微信视频通话最小化悬浮,他讲的是视频 ...

  8. android仿微信下拉二楼_Android仿微信下拉列表实现

    本文要实现微信6.1中点击顶部菜单栏的"+"号按钮时,会弹出一个列表框.这里用的了Activity实现,其实最好的方法可以用ActionBar,不过这货好像只支持3.0以后的版本. ...

  9. android java 录音放大_Android实现录音功能实现实例(MediaRecorder)

    本文介绍了Android实现录音的实例代码(MediaRecorder),分享给大家,具体如下: Android提供了两个API用于录音的实现:MediaRecorder 和 AudioRecord, ...

  10. android 辐射动画_Android仿微信雷达辐射搜索好友(逻辑清晰实现简单)

    不知不觉这个春节也已经过完了,遗憾家里没网,没能及时给大家送上祝福,今天回到深圳,明天就要上班了,小伙伴们是不是和我一样呢?今天讲的是一个大家都见过的动画,雷达搜索好友嘛,原理也十分的简单,你看完我的 ...

最新文章

  1. 无缓冲 Chan 的发送和接收是否同步
  2. html自动执行bat,html文件执行cmd指令
  3. 重载和重写以及重写的权限问题
  4. python元类单例_python面向对象和元类的理解
  5. 时间复杂度O(n^2)和O(nlog n)差距有多大?
  6. iOS开发之地图与定位
  7. 标准 C I/O函数
  8. DNF游戏私服搭建过程
  9. linux定时任务每小时_linux定时任务
  10. bash xx.sh与sh xx.sh以及./xx.sh的区别
  11. 7-4 天长地久 (20分)
  12. 苹果Mac电脑 如何设置Outlook企业邮箱
  13. WordPress教程:如何隐藏并替换WordPress管理路径?
  14. 【python学习笔记】25:scipy中值滤波
  15. 使用Amazon免费云主机和Docker,快速搭建PPTP服务器!
  16. 关于部分Vista驱动丢失的解决办法
  17. 齐鲁工业大学c语言复试真题,2016年齐鲁工业大学理学院C语言程序设计复试笔试仿真模拟题...
  18. 计算机科学技术中级职称能评吗,计算机软考中级可以评职称吗
  19. 51单片机定时器中断怎么用-------51单片机基础篇
  20. 自由职业者聚集的专业任务众包平台是怎样的? #Upwork

热门文章

  1. php获取时间戳及对时间戳进行格式化处理
  2. 日语语音识别_日语语音识别软件_日语语音识别在线 - 云+社区 - 腾讯云
  3. springboot整合author2
  4. Eclipse中文版的,怎么变成英文版
  5. sublime主题配色
  6. html5按钮超链接一个文本文档,怎么做word文档超链接
  7. 谁再说“游戏没用”,就拿这个回怼他!
  8. 彩扩机项目--开关滤波进阶,电机驱动桥,死区,三极管搭建反向电路
  9. 程序员必学的职场人际关系22原则
  10. Java Web入门之网络聊天室