為什么我點(diǎn)按鈕好長(zhǎng)時(shí)間然后松開(kāi) 總是會(huì)出現(xiàn) 錄音時(shí)間過(guò)短的對(duì)話(huà)框,只要按了按鈕。不管時(shí)間長(zhǎng)短。最后總會(huì)出現(xiàn)這個(gè)錄音時(shí)間過(guò)短的這個(gè)對(duì)話(huà)框??茨曨l看了好幾次代碼也沒(méi)錯(cuò)。
public class AudioRecorderButton extends Button implements AudioStateListener {
private static final ?int DISTANCE_YCANCEL=50;
/**
* 默認(rèn)狀態(tài)
*/
private static final int ?STATE_NORMAL=1; ? ?//默認(rèn)狀態(tài)
/**
* 錄音狀態(tài)
*/
private static final int ?STATE_RECORDING=2; ? ? ? ? //錄音狀態(tài)
/**
* 取消狀態(tài)
*/
private static final int ?STATE_WANT_TO_CANCEL=3; ? ?//取消狀態(tài)
/**
* 當(dāng)前記錄狀態(tài)
*/
private int mCurState =STATE_NORMAL; //當(dāng)前記錄狀態(tài)
/**
* 已經(jīng)開(kāi)始錄音
*/
private boolean isRecording=false;
//調(diào)用AudioManager類(lèi)。錄音
private AudioManager mAudioManager;
//調(diào)用DialogManager類(lèi)。框
private DialogManager mDialogManager;
private float mTime;
//是否觸發(fā)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);
//調(diào)用回調(diào)接口
mAudioManager.setOnAudioStateListener(this);
}
private AudioFinishRecorderListener mListener;
/**
* 定義一個(gè)接口方法,讓外部可以set調(diào)用
* @param mListener
*/
public void setAudioFinishRecorderListener(AudioFinishRecorderListener mListener)
{
this.mListener=mListener;
}
/**
* 錄音完成后的回調(diào) 接口
* @author Administrator
*
*/
public interface AudioFinishRecorderListener
{
/**
* 1.錄音的時(shí)常
* 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();
}
}
}
};
/**
* 準(zhǔn)備完全了
*/
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:
//顯示回調(diào)以后、
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實(shí)現(xiàn)回調(diào)接口方法
*/
@Override
public void wellPrepared() {
// TODO Auto-generated method stub
mHandler.sendEmptyMessage(MSG_AUDIO_PREPARED);
}
/**
* 滑動(dòng)屏幕事件。
*/
@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;
//移動(dòng)
case MotionEvent.ACTION_MOVE:
if(isRecording)
{
//根據(jù)x y的坐標(biāo),判斷是否取消
? ? ? ? ? ?if(wantToCancel(x,y))
? ? ? ? ? ?{
? ? ? ? ? ? changeState(STATE_WANT_TO_CANCEL);
? ? ? ? ? ?}else {
? ? ? ? ? ? changeState(STATE_RECORDING);
}
}
break;
? //松開(kāi)
? ?/*
? ? ? ? ?* 五種情況 1、down以后還沒(méi)觸發(fā)longclick 2、down以后觸發(fā)longClick還沒(méi)有prepaer完畢就松開(kāi)了
? ? ? ? ?* 3、錄音時(shí)間很短,沒(méi)有達(dá)到我們?cè)O(shè)定的值 4、 5、
? ? ? ? ?*/
case MotionEvent.ACTION_UP:
//判斷狀態(tài)。是否觸發(fā)longclick
//如果連ongclick也沒(méi)觸發(fā)就直接什么都不做,改變一下btooon的狀態(tài)
if(!mReady)
{
reset();
return super.onTouchEvent(event);
}
//就是說(shuō)啟動(dòng),但沒(méi)有啟動(dòng)完成
if(!isRecording || mTime < 0.5f)?
{
//顯示一個(gè)錄音太短的對(duì)話(huà)框
mDialogManager.tooShort();
mAudioManager.cancel();
//1秒后關(guān)閉dialog 延遲
mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DIMISS, 1000);
}
//根據(jù)當(dāng)前狀態(tài)==正在錄音。
else if(mCurState == ?STATE_RECORDING) //正常錄音結(jié)束
? ? ? ? ? ? ? {
? ? ? ? ? ? ?mDialogManager.dimissDialog();
? ? ? ? ? ? ?//釋放資源
? ? ? ? ? ? ?mAudioManager.release();
? ? ? ? ? ? //調(diào)用回調(diào)錄音完成后的接口
? ? ? ? ? ? ?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);
}
/**
* 按下?tīng)顟B(tài)方法
* @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;
}
}
}
/**
* 移動(dòng)狀態(tài)方法
* @param x
* @param y
* @return
*/
private boolean wantToCancel(int x, int y) {
// x<0 代碼橫坐標(biāo)已經(jīng)超出按鈕的以外,或者 ?x>getWidth()說(shuō)明到達(dá)按鈕的右部
//判斷手指已經(jīng)離開(kāi)按鈕
if(x<0 || x>getWidth())
{
return true;
}
//判斷手指的橫坐標(biāo)是否超出按鈕范圍
//如果y是在按鈕的上部或者下部超過(guò)的定義的這個(gè)DISTANCE_YCANCEL范圍
if(y < -DISTANCE_YCANCEL || y > getHeight()+DISTANCE_YCANCEL)
{
return true;
}
return false;
}
/**
* 恢復(fù)狀態(tài)及標(biāo)志位
*/
private void reset() {
? ? ?isRecording=false;
? ? ?mReady=false;
? ? ?mTime=0;
? ? ?changeState(STATE_NORMAL);
}
public class AudioManager {
/**
* 它用來(lái)記錄音頻和視頻,記錄控制基于一個(gè)簡(jiǎn)單的狀態(tài)機(jī)
*/
private MediaRecorder mMediaRecorder;
/**
* 文件夾的名稱(chēng) 因?yàn)橐浀囊旁谖募A里面
*/
private String mDir;
/**
* 因?yàn)楸4嫱暌貍鞯絙nttion
*/
private String mCurrentFilePath;
/**
* 標(biāo)記已經(jīng)state
*/
private boolean isPrepared;
/**
* 單例
*/
private static AudioManager mInstance;
/**
* 接口變量
*/
private ?AudioStateListener mListener;
/**
* 接口,
* 回調(diào)已經(jīng)完畢?
* @author Administrator
*
*/
public interface AudioStateListener
{
void wellPrepared();
}
public void setOnAudioStateListener(AudioStateListener Listener)
{
mListener=Listener;
}
//構(gòu)造方法
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;
}
/**
* 準(zhǔn)備
*/
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();
//設(shè)置輸出文件
mMediaRecorder.setOutputFile(file.getAbsolutePath());
//設(shè)置MediaRecorder的音頻源為麥克風(fēng)
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
//設(shè)置音頻的格式
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
//設(shè)置音頻的編碼為
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mMediaRecorder.prepare();
mMediaRecorder.start();
//準(zhǔn)備結(jié)束
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();
}
}
/**
* 隨即生成文件的名稱(chēng)
* @return
*/
private String generateFileName() {
return UUID.randomUUID().toString()+"amr";
}
/**
* 獲取當(dāng)前的一個(gè)音量的等級(jí)
* @param maxLevel
* @return
*/
public int getVoiceLevel(int maxLevel)
{
if(isPrepared)
{
try {
//mMediaRecorder.getMaxAmplitude()返回的是 1到32767
// mMediaRecorder.getMaxAmplitude()這個(gè)值的范圍 1-32767
//maxLevel最大為7
//得到的值在/32768 返回的0到1之間的小數(shù)。 然后再*maxLevel,在返回最小是0最大為6
//然后再加1的話(huà),就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;
}
/**
* 顯示第一個(gè)對(duì)話(huà)框。也是默認(rèn)的樣子
* 顯示錄音的對(duì)話(huà)框
*/
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("手指上滑,取消發(fā)送");
}
}
/**
* ?顯示wanToCancel的對(duì)話(huà)框
*/
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("松開(kāi)手指,取消發(fā)送");
}
}
/**
* 顯示tooShort的對(duì)話(huà)框
*/
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("錄音時(shí)間過(guò)短");
}
}
/**
* 隱藏對(duì)話(huà)框
*/
public void dimissDialog()
{
if(mDialog!=null && mDialog.isShowing())
{
mDialog.dismiss();
mDialog=null;
}
}
/**
* 通過(guò)level去更新voice上的圖片
* 更新對(duì)話(huà)框里面的音量的一個(gè)標(biāo)志
* @param level
*/
public void updateVoiceLevel(int level)
{
if(mDialog!=null && mDialog.isShowing())
{
// mIcon.setVisibility(View.VISIBLE);
// mVvoice.setVisibility(View.VISIBLE);
// mLable .setVisibility(View.VISIBLE);
/**
* 通過(guò)方法名找到資源
*/
int resId=mContext.getResources().getIdentifier("v"+level, "drawable", mContext.getPackageName());
mVvoice.setImageResource(resId);
}
}
}
2017-04-11
我也遇到了這個(gè)問(wèn)題 是因?yàn)閏hangeState函數(shù)中當(dāng)case為STATE_RECORDING時(shí)isRecording沒(méi)有設(shè)置為true,所以u(píng)p的時(shí)候調(diào)用了tooshort函數(shù)
2016-12-30
請(qǐng)問(wèn)你們解決了嗎這個(gè)問(wèn)題?我的也是,求指教,是獲得不到權(quán)限嗎?
2015-09-22
我也遇到了同樣的問(wèn)題 ?請(qǐng)問(wèn)你解決了嗎 ?是如何解決的