提要:需求是开发类似微信发语音的功能,没有语音转文字。网上看了一些代码,不能拿来直接用,部分代码逻辑有问题,所以想把自己的代码贴出来,仅供参考。
功能:
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<Boolean>() { @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
<!--App Base theme--><style name="AppthemeParent" parent="theme.AppCompat.light.NoActionbar"> <!--不显示状态栏:22之前--> <item name="androID:windowNoTitle">true</item> <item name="androID:windowAnimationStyle">@style/ActivityAnimtheme</item><!--Activity动画--> <item name="actionOverflowMenuStyle">@style/MenuStyle</item><!--toolbar菜单样式--></style><!--Dialog式的Activity--><style name="ActivityDialogStyle" parent="AppthemeParent"> <item name="androID:windowBackground">@androID:color/transparent</item> <!-- 浮于Activity之上 --> <item name="androID:windowIsfloating">true</item> <!-- 边框 --> <item name="androID:windowFrame">@null</item> <!-- Dialog以外的区域模糊效果 --> <item name="androID:backgroundDimEnabled">true</item> <!-- 半透明 --> <item name="androID:windowIsTranslucent">true</item> <!-- Dialog进入及退出动画 --> <item name="androID:windowAnimationStyle">@style/ActivityDialogAnimation</item></style><!--Audio Recorder Dialog--><style name="AudioRecorderDialogStyle" parent="ActivityDialogStyle"> <!-- Dialog以外的区域模糊效果 --> <item name="androID:backgroundDimEnabled">false</item></style><!-- Dialog动画:渐入渐出--><style name="ActivityDialogAnimation" parent="@androID:style/Animation.Dialog"> <item name="androID:windowEnteranimation">@anim/fade_in</item> <item name="androID:windowExitAnimation">@anim/fade_out</item></style>
5、DialogLayout
<?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/audio_recorder_dialog_bg" androID:gravity="center" androID:orIEntation="vertical" androID:padding="20dp"> <linearLayout androID:layout_wIDth="wrap_content" androID:layout_height="wrap_content" androID:orIEntation="horizontal"> <ImageVIEw androID:ID="@+ID/iv_dialog_icon" androID:layout_wIDth="wrap_content" androID:layout_height="wrap_content" androID:src="@drawable/ic_audio_recorder" /> <ImageVIEw androID:ID="@+ID/iv_dialog_voice" androID:layout_wIDth="wrap_content" androID:layout_height="wrap_content" androID:src="@drawable/ic_audio_v1" /> </linearLayout> <TextVIEw 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" /></linearLayout>
6、用到的字符串
<!--AudioRecord--><string name="audio_record_button_normal">按住 说话</string><string name="audio_record_button_recording">松开 结束</string><string name="audio_record_button_cancel">松开手指 取消发送</string><string name="audio_record_dialog_up_to_cancel">手指上划,取消发送</string><string name="audio_record_dialog_release_to_cancel">松开手指,取消发送</string><string name="audio_record_dialog_too_short">录音时间过短</string>
7、使用:按钮的样式不需要写在自定义button中,方便使用
<com.kIDney.base_library.vIEw.audioRecorder.AudioRecorderbutton 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仿微信录音功能所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)