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

录音时间过短显示不正常

为什么显示“录音时间过短”有问题呢?求解,谢谢了!log执行到了,就是对话框显示不正常,显示的是Normal状态

AudioRecorderButton类:

package com.imooc.recorder.view;

import android.content.Context;
import android.os.Environment;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;

import com.imooc.recorder.R;
import com.imooc.recorder.view.AudioManager.AudioStateListener;

public class AudioRecorderButton extends Button implements AudioStateListener {
	private static final int DISTANCE_Y_CANCEL = 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;
	private DialogManager mDialogManager = null;
	private AudioManager mAudioManager = null;
	/**
	 * 计时
	 */
	private float mTime;
	/**
	 * 是否触发longClick
	 */
	private boolean isReady;
	/**
	 * 最大音量
	 */
	protected static final int MAX_VOICE_LEVEL = 7;
	/**
	 * 录音完成后的回调
	 * @author Archer
	 *
	 */
	public interface AudioRecordFinishListener {
		void onFinish(float seconds, String filePath);
	}

	private AudioRecordFinishListener mListener;

	public void setOnAudioRecordFinishListener(AudioRecordFinishListener listener) {
		mListener = listener;
	}

	public AudioRecorderButton(Context context) {
		this(context, null);
	}

	public AudioRecorderButton(Context context, AttributeSet attrs) {
		super(context, attrs);

		mDialogManager = new DialogManager(getContext());
		String dir = Environment.getExternalStorageDirectory() + "/imooc_recorder_audios";
		mAudioManager = AudioManager.getInstance(dir);
		mAudioManager.setOnAudioStateListener(this);

		setOnLongClickListener(new OnLongClickListener() {

			@Override
			public boolean onLongClick(View v) {
				isReady = true;
				mAudioManager.prepareAudio();
				return false;
			}
		});
	}

	/**
	 * 获取音量大小的Runnable and 录音计时
	 */
	private Runnable mGetVoiceLevelRunnable = new Runnable() {
		@Override
		public void run() {
			while (isRecording) {
				try {
					Thread.sleep(100);
					mTime += 0.1f;
					mHandler.sendEmptyMessage(MSG_VOICE_CHANGED);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	};

	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 Handler mHandler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			switch (msg.what) {
			case MSG_AUDIO_PREPARED:
				// 显示应该在 audio end prepared 以后
				mDialogManager.showRecordingDialog();
				isRecording = true;
				new Thread(mGetVoiceLevelRunnable).start();
				break;
			case MSG_VOICE_CHANGED:
				int voiceLevel = mAudioManager.getVoiceLevel(MAX_VOICE_LEVEL);
				mDialogManager.updateVoiceLevel(voiceLevel);
				break;
			case MSG_DIALOG_DISMISS:
				mDialogManager.dismissDialog();
				break;
			}
		};
	};

	@Override
	public void wellPrepared() {
		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) {
				if (wantToCancel(x, y)) {
					changeState(STATE_WANT_TO_CANCEL);
				} else {
					changeState(STATE_RECORDING);
				}
			}
			break;

		case MotionEvent.ACTION_UP:
			if (!isReady) {
				reset();
				return super.onTouchEvent(event);
			}
			if (!isRecording || mTime < 0.6f) { // audio没有prepared 或者 mTime小于0.6f
				Log.i("recorder", "tooShort");
				mDialogManager.tooShort();
				mAudioManager.cancel();
				// 1.3s以后关闭tooShortDialog
				mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DISMISS, 1300);
			} else if (mCurState == STATE_RECORDING) { // 正常录制结束
				mDialogManager.dismissDialog();
				// audio release
				mAudioManager.release();
				// callBackToActivity
				if (mListener != null) {
					mListener.onFinish(mTime, mAudioManager.getCurrentFilePath());
				}
			} else if (mCurState == STATE_WANT_TO_CANCEL) {
				mDialogManager.dismissDialog();
				// audio cancel
				mAudioManager.cancel();
			}

			reset();
			break;
		}

		return super.onTouchEvent(event);
	}

	/**
	 * 恢复状态及标志位
	 */
	private void reset() {
		isRecording = false;
		isReady = false;
		mTime = 0;
		changeState(STATE_NORMAL);
	}

	/**
	 * 根据x,y的值判断是否想要取消
	 * 
	 * @param x
	 * @param y
	 * @return
	 */
	private boolean wantToCancel(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 (mCurState != state) {
			mCurState = state;

			switch (state) {
			case STATE_NORMAL:
				setBackgroundResource(R.drawable.btn_recorder_normal);
				setText(R.string.str_recorder_normal);
				break;
			case STATE_RECORDING:
				setBackgroundResource(R.drawable.btn_recorder_recording);
				setText(R.string.str_recorder_recording);
				if (isRecording) {
					// TODO Dialog.recording()
					mDialogManager.recording();
				}
				break;
			case STATE_WANT_TO_CANCEL:
				setBackgroundResource(R.drawable.btn_recorder_recording);
				setText(R.string.str_recorder_want_to_cancel);
				// TODO Dialog.wantToCancel()
				mDialogManager.wantToCancel();
				break;
			}
		}
	}

}
DialogManager类:

package com.imooc.recorder.view;

import android.app.Dialog;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import com.imooc.recorder.R;

public class DialogManager {
	private Context mContext;
	private Dialog mDialog;
	private ImageView mIcon;
	private ImageView mVoice;
	private TextView mLabel;

	public DialogManager(Context context) {
		mContext = context;
	}

	public void showRecordingDialog() {
		mDialog = new Dialog(mContext, R.style.Theme_AudioRecorderDialog);
		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);
		mVoice = (ImageView) mDialog.findViewById(R.id.id_recorder_dialog_voice);
		mLabel = (TextView) mDialog.findViewById(R.id.id_recorder_dialog_label);

		mDialog.show();
	}

	public void recording() {
		if (mDialog != null && mDialog.isShowing()) {
			mIcon.setVisibility(View.VISIBLE);
			mVoice.setVisibility(View.VISIBLE);
			mLabel.setVisibility(View.VISIBLE);

			mIcon.setImageResource(R.drawable.recorder);
			mLabel.setText(R.string.str_recorder_dialog_recording);
		}
	}

	public void wantToCancel() {
		if (mDialog != null && mDialog.isShowing()) {
			mIcon.setVisibility(View.VISIBLE);
			mVoice.setVisibility(View.GONE);
			mLabel.setVisibility(View.VISIBLE);

			mIcon.setImageResource(R.drawable.cancel);
			mLabel.setText(R.string.str_recorder_dialog_want_to_cancel);
		}
	}

	public void tooShort() {
		if (mDialog != null && mDialog.isShowing()) {
			mIcon.setVisibility(View.VISIBLE);
			mVoice.setVisibility(View.GONE);
			mLabel.setVisibility(View.VISIBLE);

			mIcon.setImageResource(R.drawable.voice_to_short);
			mLabel.setText(R.string.str_recorder_dialog_too_short);
		}
	}

	public void dismissDialog() {
		if (mDialog != null && mDialog.isShowing()) {
			mDialog.dismiss();
			mDialog = null;
		}
	}

	/**
	 * 通过level更新voice上的图片
	 * 
	 * @param level
	 *            1-7
	 */
	public void updateVoiceLevel(int level) {
		if (mDialog != null && mDialog.isShowing()) {
			// 通过方法名找到资源
			int resId = mContext.getResources().getIdentifier("v" + level, "drawable",
					mContext.getPackageName());
			mVoice.setImageResource(resId);
		}
	}
}
AudioManager类:

package com.imooc.recorder.view;

import java.io.File;
import java.util.UUID;

import android.media.MediaRecorder;

public class AudioManager {
	private MediaRecorder mMediaRecorder;
	private String mDir;
	private String mCurFilePath;
	private static AudioManager mInstance;
	private boolean isPrepared = false;

	public interface AudioStateListener {
		void wellPrepared();
	}

	private AudioStateListener mListener;

	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 prepareAudio() {
		try {
			isPrepared = false;
			File dir = new File(mDir);
			if (!dir.exists()) {
				dir.mkdirs();
			}
			String fileName = generateFileName();
			File file = new File(dir, fileName);
			mCurFilePath = file.getAbsolutePath();
			mMediaRecorder = new MediaRecorder();
			// 设置输出文件
			mMediaRecorder.setOutputFile(mCurFilePath);
			// 设置音频源为麦克风
			mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
			// 设置音频格式
			mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
			// 设置音频编码
			mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
			mMediaRecorder.prepare();
			mMediaRecorder.start();
			// 准备结束
			isPrepared = true;
			if (mListener != null) {
				mListener.wellPrepared();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private String generateFileName() {
		return UUID.randomUUID().toString() + ".amr";
	}

	public int getVoiceLevel(int maxLevel) {
		if (isPrepared) {
			try {
				return maxLevel * mMediaRecorder.getMaxAmplitude() / 32768 + 1;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return 1;
	}

	public void release() {
		mMediaRecorder.stop();
		mMediaRecorder.release();
		mMediaRecorder = null;
	}

	public void cancel() {
		release();
		if (mCurFilePath != null) {
			File file = new File(mCurFilePath);
			file.delete();
			mCurFilePath = null;
		}
	}

	public String getCurrentFilePath() {
		return mCurFilePath;
	}
}


正在回答

3 回答

你好,看完了你的代码没有发现问题,建议再次检查下布局文件和代码。

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

tcgwl 提问者

好的,我再对比看看吧,感谢hyman
2015-05-18 回复 有任何疑惑可以回复我~
#2

jojoyh 回复 tcgwl 提问者

我的too_short也显示不出来,你知道问题出在什么地方了吗?
2015-08-14 回复 有任何疑惑可以回复我~
#3

宇智波杰

因为start()和stop()间隔不能小于1秒,不然就会崩,stop()的时候try cache一下就行了 try { mMediaRecorder.stop(); mMediaRecorder.release(); mMediaRecorder = null; } catch (Exception e) { e.printStackTrace(); }
2016-04-28 回复 有任何疑惑可以回复我~

isReady声明时初始化为false就行了

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

你在prepareAudio()里面少一行代码。没i有设置文件输出   mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
//设置输出文件
mMediaRecorder.setOutputFile(file.getAbsolutePath());

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

举报

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

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

进入课程

录音时间过短显示不正常

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