为什么我点按钮好长时间然后松开 总是会出现 录音时间过短的对话框,只要按了按钮。不管时间长短。最后总会出现这个录音时间过短的这个对话框。看您视频看了好几次代码也没错。
public class AudioRecorderButton extends Button implements AudioStateListener {
private static final int DISTANCE_YCANCEL=50;
/**
* 默认状态
*/
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 mCurState =STATE_NORMAL; //当前记录状态
/**
* 已经开始录音
*/
private boolean isRecording=false;
//调用AudioManager类。录音
private AudioManager mAudioManager;
//调用DialogManager类。框
private DialogManager mDialogManager;
private float mTime;
//是否触发longclcik
private boolean mReady;
public AudioRecorderButton(Context context) {
this(context,null);
}
public AudioRecorderButton(Context context, AttributeSet attrs) {
super(context, attrs);
//初始化DialogManager
mDialogManager=new DialogManager(getContext());
setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View arg0) {
mReady=true;
mAudioManager.prpareAudio();
return false;
}
});
//
String dir=Environment.getExternalStorageDirectory()+"/imooc_recorder_audios";
//初始化AudioManager
mAudioManager=AudioManager.getInstance(dir);
//调用回调接口
mAudioManager.setOnAudioStateListener(this);
}
private AudioFinishRecorderListener mListener;
/**
* 定义一个接口方法,让外部可以set调用
* @param mListener
*/
public void setAudioFinishRecorderListener(AudioFinishRecorderListener mListener)
{
this.mListener=mListener;
}
/**
* 录音完成后的回调 接口
* @author Administrator
*
*/
public interface AudioFinishRecorderListener
{
/**
* 1.录音的时常
* 2.文件。地址
* @param seconds
* @param filePath
*/
public void onFinish(float seconds,String filePath);
}
/**
* 获取音量大小的Runnable
*/
private Runnable mGetVoiceLevelRunnable=new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
while(isRecording)
{
try {
Thread.sleep(100);
mHandler.sendEmptyMessage(MSG_VOICE_CHANGED_);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
/**
* 准备完全了
*/
private static final int MSG_AUDIO_PREPARED=0X110;
//
private static final int MSG_VOICE_CHANGED_=0X111;
//
private static final int MSG_DIALOG_DIMISS=0X112;
private Handler mHandler=new Handler()
{
public void handleMessage(android.os.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_DIMISS:
break;
}
};
};
/**
* AudioManager实现回调接口方法
*/
@Override
public void wellPrepared() {
// TODO Auto-generated method stub
mHandler.sendEmptyMessage(MSG_AUDIO_PREPARED);
}
/**
* 滑动屏幕事件。
*/
@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(wantToCancel(x,y))
{
changeState(STATE_WANT_TO_CANCEL);
}else {
changeState(STATE_RECORDING);
}
}
break;
//松开
/*
* 五种情况 1、down以后还没触发longclick 2、down以后触发longClick还没有prepaer完毕就松开了
* 3、录音时间很短,没有达到我们设定的值 4、 5、
*/
case MotionEvent.ACTION_UP:
//判断状态。是否触发longclick
//如果连ongclick也没触发就直接什么都不做,改变一下btooon的状态
if(!mReady)
{
reset();
return super.onTouchEvent(event);
}
//就是说启动,但没有启动完成
if(!isRecording || mTime < 0.5f)
{
//显示一个录音太短的对话框
mDialogManager.tooShort();
mAudioManager.cancel();
//1秒后关闭dialog 延迟
mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DIMISS, 1000);
}
//根据当前状态==正在录音。
else if(mCurState == STATE_RECORDING) //正常录音结束
{
mDialogManager.dimissDialog();
//释放资源
mAudioManager.release();
//调用回调录音完成后的接口
if(mListener !=null)
{
mListener.onFinish(mTime,mAudioManager.getCurrentFilePath());
}
//release
//callbackToAct
}else if(mCurState == STATE_WANT_TO_CANCEL)
{
//cancel
mDialogManager.dimissDialog();
mAudioManager.cancel();
}
reset();
break;
}
return super.onTouchEvent(event);
}
/**
* 按下状态方法
* @param stateRecording
*/
private void changeState(int state) {
if(mCurState != state)
{
mCurState=state;
switch (state) {
case STATE_NORMAL:
setBackgroundResource(R.drawable.btn_nomal);
setText(R.string.str_normal);
break;
case STATE_RECORDING:
setBackgroundResource(R.drawable.btn_recording);
setText(R.string.str_recording);
if(isRecording)
{
//更新Dialog.recording();
mDialogManager.recording();
}
break;
case STATE_WANT_TO_CANCEL:
setBackgroundResource(R.drawable.btn_recording);
setText(R.string.str_want_cancel);
mDialogManager.wanToCancel();
break;
}
}
}
/**
* 移动状态方法
* @param x
* @param y
* @return
*/
private boolean wantToCancel(int x, int y) {
// x<0 代码横坐标已经超出按钮的以外,或者 x>getWidth()说明到达按钮的右部
//判断手指已经离开按钮
if(x<0 || x>getWidth())
{
return true;
}
//判断手指的横坐标是否超出按钮范围
//如果y是在按钮的上部或者下部超过的定义的这个DISTANCE_YCANCEL范围
if(y < -DISTANCE_YCANCEL || y > getHeight()+DISTANCE_YCANCEL)
{
return true;
}
return false;
}
/**
* 恢复状态及标志位
*/
private void reset() {
isRecording=false;
mReady=false;
mTime=0;
changeState(STATE_NORMAL);
}
public class AudioManager {
/**
* 它用来记录音频和视频,记录控制基于一个简单的状态机
*/
private MediaRecorder mMediaRecorder;
/**
* 文件夹的名称 因为要录的要放在文件夹里面
*/
private String mDir;
/**
* 因为保存完要回传到bnttion
*/
private String mCurrentFilePath;
/**
* 标记已经state
*/
private boolean isPrepared;
/**
* 单例
*/
private static AudioManager mInstance;
/**
* 接口变量
*/
private AudioStateListener mListener;
/**
* 接口,
* 回调已经完毕
* @author Administrator
*
*/
public interface AudioStateListener
{
void wellPrepared();
}
public void setOnAudioStateListener(AudioStateListener Listener)
{
mListener=Listener;
}
//构造方法
private AudioManager(String dir){
mDir=dir;
}
public static AudioManager getInstance(String dir)
{
if(mInstance == null)
{
//同步
synchronized (AudioManager.class) {
if(mInstance == null)
{
mInstance=new AudioManager(dir);
}
}
}
return mInstance;
}
/**
* 准备
*/
public void prpareAudio()
{
try {
isPrepared=false;
File dir=new File(mDir);
if( !dir.exists())
dir.mkdirs();
String fileName=generateFileName();
File file=new File(dir, fileName);
//赋值
mCurrentFilePath=file.getAbsolutePath();
mMediaRecorder=new MediaRecorder();
//设置输出文件
mMediaRecorder.setOutputFile(file.getAbsolutePath());
//设置MediaRecorder的音频源为麦克风
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
//设置音频的格式
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
//设置音频的编码为
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mMediaRecorder.prepare();
mMediaRecorder.start();
//准备结束
isPrepared=true;
//通知bntton
if(mListener != null)
{
mListener.wellPrepared();
}
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 随即生成文件的名称
* @return
*/
private String generateFileName() {
return UUID.randomUUID().toString()+"amr";
}
/**
* 获取当前的一个音量的等级
* @param maxLevel
* @return
*/
public int getVoiceLevel(int maxLevel)
{
if(isPrepared)
{
try {
//mMediaRecorder.getMaxAmplitude()返回的是 1到32767
// mMediaRecorder.getMaxAmplitude()这个值的范围 1-32767
//maxLevel最大为7
//得到的值在/32768 返回的0到1之间的小数。 然后再*maxLevel,在返回最小是0最大为6
//然后再加1的话,就1到7
return maxLevel * mMediaRecorder.getMaxAmplitude()/32768+1;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return 1;
}
/**
* 释放资源
*/
public void release()
{
mMediaRecorder.stop();
mMediaRecorder.release();
mMediaRecorder=null;
}
/**
* 取消
*/
public void cancel()
{
release();
if(mCurrentFilePath !=null)
{
File file=new File(mCurrentFilePath);
file.delete();
mCurrentFilePath=null;
}
}
/**
*
* @return
*/
public String getCurrentFilePath() {
return mCurrentFilePath;
}
public class DialogManager {
private Dialog mDialog;
private ImageView mIcon;
private ImageView mVvoice;
private TextView mLable;
private Context mContext;
public DialogManager(Context context) {
mContext = context;
}
/**
* 显示第一个对话框。也是默认的样子
* 显示录音的对话框
*/
public void showRecordingDialog()
{
mDialog =new Dialog(mContext, R.style.Theme_AudioDialog);
LayoutInflater inflater=LayoutInflater.from(mContext);
View view= inflater.inflate(R.layout.dialog_recorder, null);
mDialog.setContentView(view);
mIcon=(ImageView) mDialog.findViewById(R.id.id_recorder_dialog_icon);
mVvoice=(ImageView) mDialog.findViewById(R.id.id_recorder_dialog_voice);
mLable=(TextView) mDialog.findViewById(R.id.id_recoder_dilog_lable);
mDialog.show();
}
/**
*
*/
public void recording()
{
if(mDialog!=null && mDialog.isShowing())
{
mIcon.setVisibility(View.VISIBLE);
mVvoice.setVisibility(View.VISIBLE);
mLable .setVisibility(View.VISIBLE);
mIcon.setImageResource(R.drawable.recorder);
mLable.setText("手指上滑,取消发送");
}
}
/**
* 显示wanToCancel的对话框
*/
public void wanToCancel()
{
if(mDialog!=null && mDialog.isShowing())
{
mIcon.setVisibility(View.VISIBLE);
mVvoice.setVisibility(View.GONE);
mLable .setVisibility(View.VISIBLE);
mIcon.setImageResource(R.drawable.cancel);
mLable.setText("松开手指,取消发送");
}
}
/**
* 显示tooShort的对话框
*/
public void tooShort()
{
if(mDialog!=null && mDialog.isShowing())
{
mIcon.setVisibility(View.VISIBLE);
mVvoice.setVisibility(View.GONE);
mLable .setVisibility(View.VISIBLE);
mIcon.setImageResource(R.drawable.voice_to_short);
mLable.setText("录音时间过短");
}
}
/**
* 隐藏对话框
*/
public void dimissDialog()
{
if(mDialog!=null && mDialog.isShowing())
{
mDialog.dismiss();
mDialog=null;
}
}
/**
* 通过level去更新voice上的图片
* 更新对话框里面的音量的一个标志
* @param level
*/
public void updateVoiceLevel(int level)
{
if(mDialog!=null && mDialog.isShowing())
{
// mIcon.setVisibility(View.VISIBLE);
// mVvoice.setVisibility(View.VISIBLE);
// mLable .setVisibility(View.VISIBLE);
/**
* 通过方法名找到资源
*/
int resId=mContext.getResources().getIdentifier("v"+level, "drawable", mContext.getPackageName());
mVvoice.setImageResource(resId);
}
}
}