说明
最近参考别人代码自己模仿着写了一个微信长按录音的功能
效果图
本来录完的时候那个“我是时间”应该会变为具体的时间的,但是不知道我的360奇酷手机出了什么毛病,一直不会改变,以及那个试听的语音框其实可以根据时间长短改变长度的,但是这些在我手机上都不会发生。在别的测试机上都OK。
对360奇酷手机真是醉了,不知道他们把底层给改了多少东西,前一段时间我试验5.0的新特性,它居然够本能展现那些新特性。红衣教主一直想把自己的手机往“安全”这方面发展,修改底层这么多东西,是不是给开发者也带来了很多困扰呢。
代码分析
我将代码重新整理改写成了一个小Demo
这里一共需要5个类
- Dialog管理类
这个类主要是用来创建一个Dialog,也就是录音开始的时候显示的那个Dialog,以及在不同的状态时Dialog展现不同的内容。 - Audio管理类
这个类主要是开启MediaRecorder以及管理MediaRecorder的。 - AudioRecordButton类
这个是自定义实现的Button类,继承复写了Button。 - Activity类
这个主要就是用来放内容的Activity了 - Media管理类
主要用来播放试听已录好的录音
主要代码实现
- AudioRecordButton类
public AudioRecordButton(Context context) {
this(context, null);
}
public AudioRecordButton(final Context context, AttributeSet attrs) {
super(context, attrs);
mDialogManager = new DialogManager(context);
String dir = Environment.getExternalStorageDirectory() + "/recorder_audios";
mAudioManager = AudioManager.getInstance(dir);
mAudioManager.setOnAudioStageListener(new AudioManager.AudioStageListener() {
@Override
public void wellPrepared() {
//准备好了,发送一个handler消息
mHandler.sendEmptyMessage(MSG_AUDIO_PREPARED);
}
});
setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
mAudioManager.prepareAudio();
mReady = true;
//调用手机震动器短震
Vibrator vibrator = (Vibrator) context.getSystemService(Service.VIBRATOR_SERVICE);
vibrator.vibrate(100);
return false;
}
});
}
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_AUDIO_PREPARED:
mDialogManager.showRecordingDialog();
isRecording = true;
// 需要开启一个线程来变换音量
new Thread(mGetVoiceLevelRunnable).start();
break;
case MSG_VOICE_CHANGE:
mDialogManager.updateVoiceLevel(mAudioManager.getVoiceLevel(7));
break;
case MSG_DIALOG_DISMISS:
break;
}
}
};
/**
* 录音完成后进行回调
*/
public interface AudioFinishRecorderListener {
/**
* 录音成功后可以添加的事项
*
* @param seconds 录音时间
* @param filePath 录音路径
*/
void onFinished(float seconds, String filePath);
}
private AudioFinishRecorderListener mListener;
public void setAudioFinishRecorderListener(AudioFinishRecorderListener listener) {
mListener = listener;
}
// 获取音量大小的runnable
private Runnable mGetVoiceLevelRunnable = new Runnable() {
@Override
public void run() {
while (isRecording) {
try {
Thread.sleep(100);
mTime += 0.1f;
mHandler.sendEmptyMessage(MSG_VOICE_CHANGE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
int x = (int) event.getX();
int y = (int) event.getY();
switch (action) {
case MotionEvent.ACTION_DOWN:
changeState(STATE_RECORDING);
break;
case MotionEvent.ACTION_MOVE:
if (isRecording) {
// 根据x,y来判断用户是否想要取消
if (wantToChange(x, y)) {
changeState(STATE_WANT_TO_CANCEL);
} else {
changeState(STATE_RECORDING);
}
}
break;
case MotionEvent.ACTION_UP:
if (!mReady) {
reset();
return super.onTouchEvent(event);
}
// 如果按的时间太短,还没准备好或者时间录制太短,就离开了,则显示这个dialog
if (!isRecording || mTime < 0.5f) {
mDialogManager.tooShort();
mAudioManager.cancel();
mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DISMISS, 1300);
} else if (mCurrentState == STATE_RECORDING) {//正常录制结束
mDialogManager.dismissDialog();
mAudioManager.release();
if (mListener != null) {
mListener.onFinished(mTime, mAudioManager.getCurrentFilePath());
}
} else if (mCurrentState == STATE_WANT_TO_CANCEL) {
mAudioManager.cancel();
mDialogManager.dismissDialog();
}
reset();
break;
}
return super.onTouchEvent(event);
}
/*
恢复标志位以及状态
*/
private void reset() {
isRecording = false;
changeState(STATE_NORMAL);
mReady = false;
mTime = 0;
}
/*
发生什么会取消发送
*/
private boolean wantToChange(int x, int y) {
if (x < 0 || x > getWidth()) {// 判断是否在左边,右边,上边,下边
return true;
}
if (y < -DISTANCE_Y_CANCEL || y > getHeight() + DISTANCE_Y_CANCEL) {
return true;
}
return false;
}
private void changeState(int state) {
if (mCurrentState != state) {
mCurrentState = state;
switch (mCurrentState) {
case STATE_NORMAL:
setBackgroundResource(R.drawable.button_record_normal);
setText("按住 说话");
break;
case STATE_RECORDING:
setBackgroundResource(R.drawable.button_recording);
setText("松开 结束");
if (isRecording) {
mDialogManager.recording();
}
break;
case STATE_WANT_TO_CANCEL:
setBackgroundResource(R.drawable.button_recording);
setText("松开手指,取消发送");
mDialogManager.wantToCancel();
break;
}
}
}