为了账号安全,请及时绑定邮箱和手机立即绑定

为什么我点按钮好长时间然后松开 总是会出现 录音时间过短的对话框,只要按了按钮。不管时间长短。最后总会出现这个录音时间过短的这个对话框。看您视频看了好几次代码也没错。

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);

}

}

}


正在回答

3 回答

我也遇到了这个问题 是因为changeState函数中当case为STATE_RECORDING时isRecording没有设置为true,所以up的时候调用了tooshort函数

0 回复 有任何疑惑可以回复我~

请问你们解决了吗这个问题?我的也是,求指教,是获得不到权限吗?

0 回复 有任何疑惑可以回复我~

我也遇到了同样的问题  请问你解决了吗  是如何解决的

0 回复 有任何疑惑可以回复我~
#1

慕粉1005463403

请问你们解决了吗这个问题?我的也是,求指教,是获得不到权限吗?
2016-12-30 回复 有任何疑惑可以回复我~

举报

0/150
提交
取消
Android-仿微信语音聊天
  • 参与学习       43200    人
  • 解答问题       220    个

结合自定义View和API,Dialog管理等实现实现微信语音

进入课程

为什么我点按钮好长时间然后松开 总是会出现 录音时间过短的对话框,只要按了按钮。不管时间长短。最后总会出现这个录音时间过短的这个对话框。看您视频看了好几次代码也没错。

我要回答 关注问题
意见反馈 帮助中心 APP下载
官方微信