本文是仿照张鸿洋在慕课网的教学视频《Android-仿微信语音聊天》而作,从某种意义上来说并不能算作纯粹的原创,在此首先向这位大神致敬~
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="20dp"
android:gravity="center"
android:background="@drawable/audiorec_dialog_loading_bg"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/img_recdlg_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/audiorec_recorder"
android:visibility="visible"/>
<ImageView
android:id="@+id/img_recdlg_voice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/audiorec_v1"
android:visibility="visible"/>
LinearLayout>
<TextView
android:id="@+id/txt_recdlg_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="@string/str_audiorecdlg_label_recording"
android:textColor="@color/white"/>
LinearLayout>
public void showRecordingDialog()
{
mDialog = new Dialog(mContext, R.style.Theme_AudioDialog);
LayoutInflater inflater = LayoutInflater.from(mContext);
View view = inflater.inflate(R.layout.layout_dialog_rec,null);
mDialog.setContentView(view);
mIcon = (ImageView) mDialog.findViewById(R.id.img_recdlg_icon);
mVoice = (ImageView) mDialog.findViewById(R.id.img_recdlg_voice);
mLabel = (TextView) mDialog.findViewById(R.id.txt_recdlg_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.audiorec_recorder);
mLabel.setText(R.string.str_audiorecdlg_label_recording);
}
}
/**
* 更新声音级别的图片
* @param level must be 1-7
*/
public void updateVoiceLevel(int level)
{
if (mDialog != null && mDialog.isShowing())
{
//通过level获取resId
int resId = mContext.getResources().getIdentifier("audiorec_v"+level,
"drawable",mContext.getPackageName());
mVoice.setImageResource(resId);
}
}
public void wangToCancel()
{
if (mDialog != null && mDialog.isShowing())
{
mIcon.setVisibility(View.VISIBLE);
mVoice.setVisibility(View.GONE);
mLabel.setVisibility(View.VISIBLE);
mIcon.setImageResource(R.drawable.audiorec_cancel);
mLabel.setText(R.string.str_audiorecbtn_want_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.audiorec_voice_too_short);
mLabel.setText(R.string.str_audiorecdlg_label_too_short);
}
}
<string name="str_audiorecbtn_want_cancel">松开手指,取消发送string>
<string name="str_audiorecdlg_label_recording">手指上滑,取消发送string>
<string name="str_audiorecdlg_label_too_short">录音时间过短string>
public void prepareAudio() //准备
{
String strPath = MediaManager.getInstance().getStoragePath(MediaManager.MediaType.AUDIO_UPLOAD);
String fileName = "voice_"+System.currentTimeMillis()+".amr";
curFile = new File(strPath,fileName);
isPrepared = false;
recorder = new MediaRecorder();
recorder.setOutputFile(curFile.getAbsolutePath());
recorder.setAudioSource(MediaRecorder.AudioSource.MIC); //音频源为麦克风
recorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB); //输出文件格式
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); //音频编码格式
try
{
recorder.prepare();
recorder.start(); //已经准备好
isPrepared = true;
if( null != listener )
{
listener.onPrepared();
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
//接口
private AudioStateListener listener;
public interface AudioStateListener
{
void onPrepared(); //回调 准备完毕
}
public void setOnAudioStateListener( AudioStateListener listener)
{
this.listener = listener;
}
public int getVoiceVolume( int maxLevel ) //音量等级
{
if( isPrepared )
{
try {
//振幅范围是 1-32767
return maxLevel * recorder.getMaxAmplitude() / 32768 + 1;
} catch (Exception e) {}
}
return 1;
}
public void release() //释放
{
recorder.stop();
recorder.release();
recorder = null;
}
public void cancel() //取消
{
release();
if( null != curFile )
{
curFile.delete();
curFile = null;
}
}
//Y方向按住移动此距离后更改状态为试图取消
private static final int DISTANCE_Y_CANCEL = 50;
//最大声音级别
private static final int MAX_VOLUME_LEVEL = 7;
//最短录音时长
private static final float LEAST_REC_TIME = 1.0f;
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; //录音准备是否已经完成
private boolean mReady; //是否已经进入录音状态
private float mTime; //计时
VoiceRecorder.AudioStateListener asListener = new VoiceRecorder.AudioStateListener()
{
@Override
public void onPrepared()
{
mHandler.sendEmptyMessage(MSG_AUDIO_PREPARED);
}
};
private static final int MSG_AUDIO_PREPARED = 0x100;
private static final int MSG_VOICE_CHANGED = 0x101;
private static final int MSG_DIALOG_DISMISS = 0x102;
private Handler mHandler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
switch (msg.what)
{
case MSG_AUDIO_PREPARED:
mDialogManager.showRecordingDialog();
isRecording = true;
new Thread(mGetVolume).start(); //开启新线程,记录录音时间,并不断获取音量
break;
case MSG_VOICE_CHANGED:
mDialogManager.updateVoiceLevel(
VoiceRecorder.getInstance().getVoiceVolume(MAX_VOLUME_LEVEL));
break;
case MSG_DIALOG_DISMISS:
mDialogManager.dismissDialog();
break;
}
}
};
//获取音量大小
private Runnable mGetVolume = 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 void changeState(int state)
{
if (mCurState != state)
{
mCurState = state;
switch (state)
{
case STATE_NORMAL:
setBackgroundResource(R.drawable.im_controlbar_inputbox_n);
setText(R.string.str_audiorecbtn_normal);
break;
case STATE_RECORDING:
if(mReady == false)
{
mReady = true;
VoiceRecorder.getInstance().prepareAudio();
}
setBackgroundResource(R.drawable.im_controlbar_inputbox_p);
setText(R.string.str_audiorecbtn_recording);
if (isRecording)
{
mDialogManager.recording();
}
break;
case STATE_WANT_TO_CANCEL:
setBackgroundResource(R.drawable.im_controlbar_inputbox_p);
setText(R.string.str_audiorecbtn_want_cancel);
mDialogManager.wangToCancel();
break;
default:
break;
}
}
}
@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:
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
}
return super.onTouchEvent(event);
}
case MotionEvent.ACTION_DOWN:
reset();
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(!mReady) //状态还没切换
{
reset();
mDialogManager.showRecordingDialog();
mDialogManager.tooShort();
mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DISMISS, 1300);
return super.onTouchEvent(event);
}
if( !isRecording || mTime < LEAST_REC_TIME ) //prepare还没完成 或 录音时间太短
{
VoiceRecorder.getInstance().cancel();
if(STATE_RECORDING == mCurState)
{
mDialogManager.tooShort();
mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DISMISS,1300);
}
else
{
mDialogManager.dismissDialog();
}
}
else if (STATE_RECORDING == mCurState) //正常录制结束
{
mDialogManager.dismissDialog();
VoiceRecorder.getInstance().release();
if( listener != null)
{
listener.onRecordFinish(mTime,VoiceRecorder.getInstance().getFilePath());
}
}
else if (STATE_WANT_TO_CANCEL == mCurState) //取消录音
{
mDialogManager.dismissDialog();
VoiceRecorder.getInstance().cancel();
}
reset();
break;
//录音完成回调接口
public interface OnRecordFinishListener
{
void onRecordFinish(float seconds, String fileName);
}
private OnRecordFinishListener listener;
public void setOnRecordFinishListener( OnRecordFinishListener listener )
{
this.listener = listener;
}
public class MediaManager
{
private static MediaManager mInstance;
private static final String AUDIO_DIR = "/im/audio";
private static final String AUDIO_UPLOAD_DIR = "/im/audio/upload";
private MediaManager() {}
public static MediaManager getInstance()
{
if (null == mInstance)
{
synchronized (MediaManager.class)
{
if (null == mInstance)
{
mInstance = new MediaManager();
}
}
}
return mInstance;
}
private MediaPlayer mMediaPlayer;
private boolean isPause; //当前是否暂停
public String getStoragePath(MediaType type)
{
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
{
String sdcardPath = Environment.getExternalStorageDirectory().getAbsolutePath();
File dir = null;
switch (type)
{
case AUDIO:
dir = new File(sdcardPath + AUDIO_DIR);
break;
case AUDIO_UPLOAD:
dir = new File(sdcardPath + AUDIO_UPLOAD_DIR);
break;
}
if (!dir.exists())
{
dir.mkdirs();
}
return dir.getAbsolutePath();
}
else
{
return null;
}
}
public void playSound(String filePath, MediaPlayer.OnCompletionListener listener)
{
if (null == mMediaPlayer)
{
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener()
{
@Override
public boolean onError(MediaPlayer mp, int what, int extra)
{
mMediaPlayer.reset();
return false;
}
});
}
else
{
mMediaPlayer.reset();
}
try
{
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setOnCompletionListener(listener);
mMediaPlayer.setDataSource(filePath);
mMediaPlayer.prepare();
mMediaPlayer.start();
}
catch (IOException e)
{
e.printStackTrace();
}
}
public void pause()
{
if (null != mMediaPlayer && mMediaPlayer.isPlaying())
{
mMediaPlayer.pause();
isPause = true;
}
}
public void resume()
{
if (null != mMediaPlayer && isPause)
{
mMediaPlayer.start();
isPause = false;
}
}
public void release()
{
if (null != mMediaPlayer)
{
mMediaPlayer.release();
mMediaPlayer = null;
}
}
public enum MediaType
{
AUDIO,
AUDIO_UPLOAD,
}
}
AudioRecorderButton.OnRecordFinishListener orfListener = new AudioRecorderButton.OnRecordFinishListener()
{
@Override
public void onRecordFinish(float seconds, String fileName)
{
uploadAudio(new File(fileName), Math.round(seconds), new Callback()
{
@Override
public void onFailure(Exception e)
{
}
@Override
public void onSuccess()
{
//其他操作,添加到listview等等
}
});
}
};
源码下载链接:http://download.csdn.net/detail/liusiqian0209/9265237