这是从公司项目里面的抽取出来的,开发过程中也碰到很多问题,基本上满足了一些需求,话不多少,看效果,上代码。。。。
1,给录音数据设置一个存放路径:
/**
* 录音存放路径
*/
public void initSoundData() {
dataPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/AsRecrod/Sounds/";
File folder = new File(dataPath);
if (!folder.exists()) {
folder.mkdirs();
}
mMediaPlayUtil = MediaPlayUtil.getInstance();
}
在ACTION_DOWM中,初始化一些东西,开始录音,并开启录音计时和录音时的动画
在ACTION_MOVE中,监听手指滑动的距离,往上滑动时提示取消录音
在ACTION_UP中,如果没有超时,结束录音,显示录音
在ACTION_CANCEL中,有的手机第一次录音时会提示开启录音权限,在点击开始权限时,会走到这里面,需要,清空数据,否则会出现录音失败,设置程序崩溃,很重要
/**
* 录音的触摸监听
*/
class VoiceTouch implements View.OnTouchListener {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
downY = motionEvent.getY();
mIvRecord.setImageDrawable(getResources().getDrawable(R.drawable.record_pressed));
mTvNotice.setText("向上滑动取消发送");
mSoundData = dataPath + getRandomFileName() + ".amr";
// TODO 防止开权限后崩溃
if (mRecorder != null) {
mRecorder.reset();
} else {
mRecorder = new MediaRecorder();
}
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);
mRecorder.setOutputFile(mSoundData);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
try {
mRecorder.prepare();
} catch (IOException e) {
Log.i("recoder", "prepare() failed-Exception-" + e.toString());
}
try {
mRecorder.start();
mStartTime = System.currentTimeMillis();
mSoundLengthLayout.setVisibility(View.VISIBLE);
mTvTime.setText("0" + '"');
// TODO 开启定时器
mHandler.postDelayed(runnable, 1000);
} catch (Exception e) {
Log.i("recoder", "prepare() failed-Exception-"+e.toString());
}
initScaleAnim();
// TODO 录音过程重复动画
mScaleBigAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
if (mScaleLittleAnimation != null) {
mIvRecord.startAnimation(mScaleLittleAnimation);
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
mScaleLittleAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
if (mScaleBigAnimation != null) {
mIvRecord.startAnimation(mScaleBigAnimation);
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
mIvRecord.startAnimation(mScaleBigAnimation);
break;
case MotionEvent.ACTION_UP:
if (!isStop) {
mEndTime = System.currentTimeMillis();
mTime = (int) ((mEndTime - mStartTime) / 1000);
stopRecord();
mIvRecord.setVisibility(View.VISIBLE);
try {
mVoiceData = StringUtil.encodeBase64File(mSoundData);
} catch (Exception e) {
e.printStackTrace();
}
if (isCanceled) {
deleteSoundFileUnSend();
mTvTime.setText("0" +'"' );
mTvNotice.setText("录音取消");
mRlVoiceLayout.setVisibility(View.GONE);
} else {
mIvRecord.setImageDrawable(getResources().getDrawable(R.drawable.record));
mRlVoiceLayout.setVisibility(View.VISIBLE);
mTvTimeLengh.setText(mTime + "" +'"' );
}
}else{
mTvTime.setText("0");
mIvRecord.setImageDrawable(getResources().getDrawable(R.drawable.record));
mTvNotice.setText("重新录音");
}
break;
case MotionEvent.ACTION_CANCEL: // 首次开权限时会走这里,录音取消
Log.i("record_test","权限影响录音录音");
mHandler.removeCallbacks(runnable);
mSoundLengthLayout.setVisibility(View.GONE);
// TODO 这里一定注意,先release,还要置为null,否则录音会发生错误,还有可能崩溃
if (mRecorder != null) {
mRecorder.release();
mRecorder = null;
System.gc();
}
mIvRecord.setImageDrawable(getResources().getDrawable(R.drawable.record));
mIvRecord.clearAnimation();
mTvNotice.setText("按住说话");
isCanceled = true;
mScaleBigAnimation = null;
mScaleLittleAnimation = null;
break;
case MotionEvent.ACTION_MOVE: // 滑动手指
float moveY = motionEvent.getY();
if (downY - moveY > 100) {
isCanceled = true;
mTvNotice.setText("松开手指可取消录音");
mIvRecord.setImageDrawable(getResources().getDrawable(R.drawable.record));
}
if (downY - moveY < 20) {
isCanceled = false;
mIvRecord.setImageDrawable(getResources().getDrawable(R.drawable.record_pressed));
mTvNotice.setText("向上滑动取消发送");
}
break;
}
return true;
}
}
3,定时器,这里采用handler,每隔一秒判断一下时间
// 定时器
Runnable runnable = new Runnable() {
@Override
public void run() {
// handler自带方法实现定时器
try {
long endTime = System.currentTimeMillis();
int time = (int) ((endTime - mStartTime) / 1000);
//mRlSoundLengthLayout.setVisibility(View.VISIBLE);
mTvTime.setText(time + "" + '"');
// 限制录音时间不长于两分钟
if (time > 119) {
isStop = true;
mTime = time;
stopRecord();
Toast.makeText(MyActivity.this, "时间过长", Toast.LENGTH_SHORT).show();
} else {
mHandler.postDelayed(this, 1000);
isStop = false;
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
4,结束录音,清空一些数据,防止对下次录音有影响
/**
* 结束录音
*/
public void stopRecord() {
mIvRecord.clearAnimation();
mScaleBigAnimation = null;
mScaleLittleAnimation = null;
if (mTime < 1) {
deleteSoundFileUnSend();
isCanceled = true;
Toast.makeText(MyActivity.this, "录音时间太短,长按开始录音", Toast.LENGTH_SHORT).show();
} else {
mTvNotice.setText("录音成功");
// 不加 "" 空串 会出 Resources$NotFoundException 错误
mTvTime.setText(mTime + "" + '"');
Log.i("record_test","录音成功");
}
//mRecorder.setOnErrorListener(null);
try {
mRecorder.stop();
mRecorder.reset();
mRecorder.release();
} catch (Exception e) {
Log.i("recoder", "stop() failed");
isCanceled = true;
mIvRecord.setVisibility(View.VISIBLE);
mTvTime.setText("");
Toast.makeText(MyActivity.this, "录音发生错误,请重新录音", Toast.LENGTH_LONG).show();
Log.i("record_test","录音发生错误");
}
mHandler.removeCallbacks(runnable);
if (mRecorder != null) {
mRecorder = null;
System.gc();
}
}
5,播放录音,这里是仿微信的效果,凑合凑合吧
// TODO 播放录音
mRlVoiceLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mMediaPlayUtil.isPlaying()) {
mMediaPlayUtil.stop();
mImageAnim.stop();
mIvVoice.setVisibility(View.VISIBLE);
mIvVoiceAnim.setVisibility(View.GONE);
} else {
startAnim();
mMediaPlayUtil.play(StringUtil.decoderBase64File(mVoiceData));
}
}
});
/**
* 语音播放效果
*
*/
public void startAnim() {
mImageAnim = (AnimationDrawable) mIvVoiceAnim.getBackground();
mIvVoiceAnim.setVisibility(View.VISIBLE);
mIvVoice.setVisibility(View.GONE);
mImageAnim.start();
mMediaPlayUtil.setPlayOnCompleteListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
mIvVoice.setVisibility(View.VISIBLE);
mIvVoiceAnim.setVisibility(View.GONE);
}
});
}
6,不要忘了添加权限
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
7,源码下载地址: http://download.youkuaiyun.com/detail/qq55214/9456371