项目效果如下:


AudioManager.java
-
package com.xuliugen.weichat;
-
import java.io.File;
-
import java.io.IOException;
-
import java.util.UUID;
-
import android.media.MediaRecorder;
-
publicclassAudioManager{
-
privateMediaRecorder mMediaRecorder;
-
privateString mDir;
-
privateString mCurrentFilePath;
-
privatestaticAudioManager mInstance;
-
privateboolean isPrepare;
-
privateAudioManager(String dir){
-
mDir = dir;
- }
-
publicstaticAudioManager getInstance(String dir){
-
if(mInstance ==null){
-
synchronized(AudioManager.class){
-
if(mInstance ==null){
-
mInstance =newAudioManager(dir);
- }
- }
- }
-
return mInstance;
- }
- /** * 使用接口 用于回调 */
-
publicinterfaceAudioStateListener{
-
void wellPrepared();
- }
-
publicAudioStateListener mAudioStateListener;
- /** * 回调方法 */
-
publicvoid setOnAudioStateListener(AudioStateListener listener){
-
mAudioStateListener = listener;
- }
- // 去准备
-
publicvoid prepareAudio(){
-
try{
-
isPrepare =false;
-
File dir =newFile(mDir);
-
if(!dir.exists()){
-
dir.mkdirs();
- }
-
String fileName = generateFileName();
-
File file =newFile(dir, fileName);
-
mCurrentFilePath =file.getAbsolutePath();
-
mMediaRecorder =newMediaRecorder();
- // 设置输出文件
-
mMediaRecorder.setOutputFile(dir.getAbsolutePath());
- // 设置MediaRecorder的音频源为麦克风
-
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
- // 设置音频格式
-
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
- // 设置音频编码
-
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
- // 准备录音
-
mMediaRecorder.prepare();
- // 开始
-
mMediaRecorder.start();
- // 准备结束
-
isPrepare =true;
-
if(mAudioStateListener !=null){
-
mAudioStateListener.wellPrepared();
- }
-
}catch(IllegalStateException e){
-
e.printStackTrace();
-
}catch(IOException e){
-
e.printStackTrace();
- }
- }
- /** * 随机生成文件的名称 */
-
privateString generateFileName(){
-
return UUID.randomUUID().toString()+".amr";
- }
-
publicint getVoiceLevel(int maxlevel){
-
if(isPrepare){
-
try{
- // mMediaRecorder.getMaxAmplitude() 1~32767
-
return maxlevel * mMediaRecorder.getMaxAmplitude()/32768+1;
-
}catch(Exception e){
- }
- }
-
return1;
- }
- /** * 释放资源 */
-
publicvoid release(){
- //mMediaRecorder.stop();
-
mMediaRecorder.reset();
-
mMediaRecorder =null;
- }
- /** * 取消录音 */
-
publicvoid cancel(){
-
release();
-
if(mCurrentFilePath !=null){
-
File file =newFile(mCurrentFilePath);
-
file.delete();
-
mCurrentFilePath =null;
- }
- }
-
publicString getCurrentFilePath(){
-
return mCurrentFilePath;
- }
- }
AudioRecorderButton.java
-
package com.xuliugen.weichat;
-
import android.content.Context;
-
import android.os.Environment;
-
import android.os.Handler;
-
import android.os.Message;
-
import android.util.AttributeSet;
-
import android.view.MotionEvent;
-
import android.view.View;
-
import android.widget.Button;
-
import com.xuliugen.weichat.R;
-
import com.xuliugen.weichat.AudioManager.AudioStateListener;
-
publicclassAudioRecorderButtonextendsButton{
-
privatestaticfinalint STATE_NORMAL =1;// 默认的状态
-
privatestaticfinalint STATE_RECORDING =2;// 正在录音
-
privatestaticfinalint STATE_WANT_TO_CANCEL =3;// 希望取消
-
privateint mCurrentState = STATE_NORMAL;// 当前的状态
-
privateboolean isRecording =false;// 已经开始录音
-
privatestaticfinalint DISTANCE_Y_CANCEL =50;
-
privateDialogManager mDialogManager;
-
privateAudioManager mAudioManager;
-
privatefloat mTime;
- // 是否触发longClick
-
privateboolean mReady;
-
privatestaticfinalint MSG_AUDIO_PREPARED =0x110;
-
privatestaticfinalint MSG_VOICE_CHANGED =0x111;
-
privatestaticfinalint MSG_DIALOG_DIMISS =0x112;
- /* * 获取音量大小的线程 */
-
privateRunnable mGetVoiceLevelRunnable =newRunnable(){
-
publicvoid run(){
-
while(isRecording){
-
try{
-
Thread.sleep(100);
-
mTime +=0.1f;
-
mHandler.sendEmptyMessage(MSG_VOICE_CHANGED);
-
}catch(InterruptedException e){
-
e.printStackTrace();
- }
- }
- }
- };
-
privateHandler mHandler =newHandler(){
- @Override
-
publicvoid handleMessage(Message msg){
-
switch(msg.what){
-
case MSG_AUDIO_PREPARED:
- // 显示對話框在开始录音以后
-
mDialogManager.showRecordingDialog();
-
isRecording =true;
- // 开启一个线程
-
newThread(mGetVoiceLevelRunnable).start();
-
break;
-
case MSG_VOICE_CHANGED:
-
mDialogManager.updateVoiceLevel(mAudioManager.getVoiceLevel(7));
-
break;
-
case MSG_DIALOG_DIMISS:
-
mDialogManager.dimissDialog();
-
break;
- }
-
super.handleMessage(msg);
- }
- };
- /** * 以下2个方法是构造方法 */
-
publicAudioRecorderButton(Context context,AttributeSet attrs){
-
super(context, attrs);
-
mDialogManager =newDialogManager(context);
-
String dir ="/storage/sdcard0/my_weixin";
- //String dir = Environment.getExternalStorageDirectory()+"/my_weixin";
-
mAudioManager =AudioManager.getInstance(dir);
-
mAudioManager.setOnAudioStateListener(newAudioStateListener(){
-
publicvoid wellPrepared(){
-
mHandler.sendEmptyMessage(MSG_AUDIO_PREPARED);
- }
- });
- // 由于这个类是button所以在构造方法中添加监听事件
-
setOnLongClickListener(newOnLongClickListener(){
-
publicboolean onLongClick(View v){
-
mReady =true;
-
mAudioManager.prepareAudio();
-
returnfalse;
- }
- });
- }
-
publicAudioRecorderButton(Context context){
-
this(context,null);
- }
- /** * 录音完成后的回调 */
-
publicinterfaceAudioFinishRecorderListener{
-
void onFinish(float seconds,String filePath);
- }
-
privateAudioFinishRecorderListener audioFinishRecorderListener;
-
publicvoid setAudioFinishRecorderListener(AudioFinishRecorderListener listener){
-
audioFinishRecorderListener = listener;
- }
- /** * 屏幕的触摸事件 */
- @Override
-
publicboolean onTouchEvent(MotionEventevent){
-
int action =event.getAction();
-
int x =(int)event.getX();// 获得x轴坐标
-
int y =(int)event.getY();// 获得y轴坐标
-
switch(action){
-
caseMotionEvent.ACTION_DOWN:
-
changeState(STATE_RECORDING);
-
break;
-
caseMotionEvent.ACTION_MOVE:
-
if(isRecording){
- // 如果想要取消,根据x,y的坐标看是否需要取消
-
if(wantToCancle(x, y)){
-
changeState(STATE_WANT_TO_CANCEL);
-
}else{
-
changeState(STATE_RECORDING);
- }
- }
-
break;
-
caseMotionEvent.ACTION_UP:
-
if(!mReady){
-
reset();
-
returnsuper.onTouchEvent(event);
- }
-
if(!isRecording || mTime <0.6f){
-
mDialogManager.tooShort();
-
mAudioManager.cancel();
-
mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DIMISS,1000);// 延迟显示对话框
-
}elseif(mCurrentState == STATE_RECORDING){// 正在录音的时候,结束
-
mDialogManager.dimissDialog();
-
mAudioManager.release();
-
if(audioFinishRecorderListener !=null){
-
audioFinishRecorderListener.onFinish(mTime,mAudioManager.getCurrentFilePath());
- }
-
}elseif(mCurrentState == STATE_WANT_TO_CANCEL){// 想要取消
-
mDialogManager.dimissDialog();
-
mAudioManager.cancel();
- }
-
reset();
-
break;
- }
-
returnsuper.onTouchEvent(event);
- }
- /** * 恢复状态及标志位 */
-
privatevoid reset(){
-
isRecording =false;
-
mTime =0;
-
mReady =false;
-
changeState(STATE_NORMAL);
- }
-
privateboolean wantToCancle(int x,int y){
-
if(x <0|| x > getWidth()){// 超过按钮的宽度
-
returntrue;
- }
- // 超过按钮的高度
-
if(y <-DISTANCE_Y_CANCEL || y > getHeight()+ DISTANCE_Y_CANCEL){
-
returntrue;
- }
-
returnfalse;
- }
- /** * 改变 */
-
privatevoid changeState(int state){
-
if(mCurrentState != state){
-
mCurrentState = 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){
-
mDialogManager.recording();
- }
-
break;
-
case STATE_WANT_TO_CANCEL:
-
setBackgroundResource(R.drawable.btn_recorder_recording);
-
setText(R.string.str_recorder_want_cancel);
-
mDialogManager.wantToCancel();
-
break;
- }
- }
- }
- }
DialogManager.java
-
package com.xuliugen.weichat;
-
import android.app.AlertDialog;
-
import android.content.Context;
-
import android.view.LayoutInflater;
-
import android.view.View;
-
import android.widget.ImageView;
-
import android.widget.TextView;
-
import com.xuliugen.weichat.R;
- /** * 用于管理Dialog * * @author xuliugen * */
-
publicclassDialogManager{
-
privateAlertDialog.Builder builder;
-
privateImageView mIcon;
-
privateImageView mVoice;
-
privateTextView mLable;
-
privateContext mContext;
-
privateAlertDialog dialog;//用于取消AlertDialog.Builder
- /** * 构造方法 传入上下文 */
-
publicDialogManager(Context context){
-
this.mContext = context;
- }
- // 显示录音的对话框
-
publicvoid showRecordingDialog(){
-
builder =newAlertDialog.Builder(mContext, R.style.AudioDialog);
-
LayoutInflater inflater =LayoutInflater.from(mContext);
-
View view = inflater.inflate(R.layout.dialog_recorder,null);
-
mIcon =(ImageView) view.findViewById(R.id.id_recorder_dialog_icon);
-
mVoice =(ImageView) view.findViewById(R.id.id_recorder_dialog_voice);
-
mLable =(TextView) view.findViewById(R.id.id_recorder_dialog_label);
-
builder.setView(view);
-
builder.create();
-
dialog = builder.show();
- }
-
publicvoid recording(){
-
if(dialog !=null&& dialog.isShowing()){//显示状态
-
mIcon.setVisibility(View.VISIBLE);
-
mVoice.setVisibility(View.VISIBLE);
-
mLable.setVisibility(View.VISIBLE);
-
mIcon.setImageResource(R.drawable.recorder);
-
mLable.setText("手指上滑,取消发送");
- }
- }
- // 显示想取消的对话框
-
publicvoid wantToCancel(){
-
if(dialog !=null&& dialog.isShowing()){//显示状态
-
mIcon.setVisibility(View.VISIBLE);
-
mVoice.setVisibility(View.GONE);
-
mLable.setVisibility(View.VISIBLE);
-
mIcon.setImageResource(R.drawable.cancel);
-
mLable.setText("松开手指,取消发送");
- }
- }
- // 显示时间过短的对话框
-
publicvoid tooShort(){
-
if(dialog !=null&& dialog.isShowing()){//显示状态
-
mIcon.setVisibility(View.VISIBLE);
-
mVoice.setVisibility(View.GONE);
-
mLable.setVisibility(View.VISIBLE);
-
mIcon.setImageResource(R.drawable.voice_to_short);
-
mLable.setText("录音时间过短");
- }
- }
- // 显示取消的对话框
-
publicvoid dimissDialog(){
-
if(dialog !=null&& dialog.isShowing()){//显示状态
-
dialog.dismiss();
-
dialog =null;
- }
- }
- // 显示更新音量级别的对话框
-
publicvoid updateVoiceLevel(int level){
-
if(dialog !=null&& dialog.isShowing()){//显示状态
- // mIcon.setVisibility(View.VISIBLE);
- // mVoice.setVisibility(View.VISIBLE);
- // mLable.setVisibility(View.VISIBLE);
- //设置图片的id
-
int resId = mContext.getResources().getIdentifier("v"+level,"drawable", mContext.getPackageName());
-
mVoice.setImageResource(resId);
- }
- }
- }
MainActivity.java
-
package com.xuliugen.weichat;
-
import java.util.ArrayList;
-
import java.util.List;
-
import com.xuliugen.weichat.AudioRecorderButton.AudioFinishRecorderListener;
-
import android.app.Activity;
-
import android.graphics.drawable.AnimationDrawable;
-
import android.media.MediaPlayer;
-
import android.os.Bundle;
-
import android.view.View;
-
import android.widget.AdapterView;
-
import android.widget.ArrayAdapter;
-
import android.widget.ListView;
-
import android.widget.AdapterView.OnItemClickListener;
-
publicclassMainActivityextendsActivity{
-
privateListView mListView;
-
privateArrayAdapter<Recorder> mAdapter;
-
privateList<Recorder> mDatas =newArrayList<MainActivity.Recorder>();
-
privateAudioRecorderButton mAudioRecorderButton;
-
privateView animView;
- @Override
-
protectedvoid onCreate(Bundle savedInstanceState){
-
super.onCreate(savedInstanceState);
-
setContentView(R.layout.activity_main);
-
mListView =(ListView) findViewById(R.id.id_listview);
-
mAudioRecorderButton =(AudioRecorderButton) findViewById(R.id.id_recorder_button);
-
mAudioRecorderButton.setAudioFinishRecorderListener(newAudioFinishRecorderListener(){
-
publicvoid onFinish(float seconds,String filePath){
-
Recorder recorder =newRecorder(seconds, filePath);
-
mDatas.add(recorder);
-
mAdapter.notifyDataSetChanged();//通知更新的内容
-
mListView.setSelection(mDatas.size()-1);//将lisview设置为最后一个
- }
- });
-
mAdapter =newRecoderAdapter(this, mDatas);
-
mListView.setAdapter(mAdapter);
- //listView的item点击事件
-
mListView.setOnItemClickListener(newOnItemClickListener(){
-
publicvoid onItemClick(AdapterView<?> arg0,View view,int position,long id){
- // 播放动画(帧动画)
-
if(animView !=null){
-
animView.setBackgroundResource(R.drawable.adj);
-
animView =null;
- }
-
animView = view.findViewById(R.id.id_recoder_anim);
-
animView.setBackgroundResource(R.drawable.play_anim);
-
AnimationDrawable animation =(AnimationDrawable) animView.getBackground();
-
animation.start();
- // 播放录音
-
MediaManager.playSound(mDatas.get(position).filePath,newMediaPlayer.OnCompletionListener(){
-
publicvoid onCompletion(MediaPlayer mp){
-
animView.setBackgroundResource(R.drawable.adj);
- }
- });
- }
- });
- }
- @Override
-
protectedvoid onPause(){
-
super.onPause();
-
MediaManager.pause();
- }
- @Override
-
protectedvoid onResume(){
-
super.onResume();
-
MediaManager.resume();
- }
- @Override
-
protectedvoid onDestroy(){
-
super.onDestroy();
-
MediaManager.release();
- }
-
classRecorder{
-
float time;
-
String filePath;
-
publicRecorder(float time,String filePath){
-
super();
-
this.time = time;
-
this.filePath = filePath;
- }
-
publicfloat getTime(){
-
return time;
- }
-
publicvoid setTime(float time){
-
this.time = time;
- }
-
publicString getFilePath(){
-
return filePath;
- }
-
publicvoid setFilePath(String filePath){
-
this.filePath = filePath;
- }
- }
- }
MediaManager.java
-
package com.xuliugen.weichat;
-
import android.media.AudioManager;
-
import android.media.MediaPlayer;
-
import android.media.MediaPlayer.OnCompletionListener;
-
import android.media.MediaPlayer.OnErrorListener;
-
publicclassMediaManager{
-
privatestaticMediaPlayer mMediaPlayer;
-
privatestaticboolean isPause;
- /** * 播放音乐 * @param filePath * @param onCompletionListener */
-
publicstaticvoid playSound(String filePath,OnCompletionListener onCompletionListener){
-
if(mMediaPlayer ==null){
-
mMediaPlayer =newMediaPlayer();
- //设置一个error监听器
-
mMediaPlayer.setOnErrorListener(newOnErrorListener(){
-
publicboolean onError(MediaPlayer arg0,int arg1,int arg2){
-
mMediaPlayer.reset();
-
returnfalse;
- }
- });
-
}else{
-
mMediaPlayer.reset();
- }
-
try{
-
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
-
mMediaPlayer.setOnCompletionListener(onCompletionListener);
-
mMediaPlayer.setDataSource(filePath);
-
mMediaPlayer.prepare();
-
mMediaPlayer.start();
-
}catch(Exception e){
- }
- }
- /** * 暂停播放 */
-
publicstaticvoid pause(){
-
if(mMediaPlayer !=null&& mMediaPlayer.isPlaying()){//正在播放的时候
-
mMediaPlayer.pause();
-
isPause =true;
- }
- }
- /** * 当前是isPause状态 */
-
publicstaticvoid resume(){
-
if(mMediaPlayer !=null&& isPause){
-
mMediaPlayer.start();
-
isPause =false;
- }
- }
- /** * 释放资源 */
-
publicstaticvoid release(){
-
if(mMediaPlayer !=null){
-
mMediaPlayer.release();
-
mMediaPlayer =null;
- }
- }
- }
RecoderAdapter.java
-
package com.xuliugen.weichat;
-
import java.util.List;
-
import android.content.Context;
-
import android.util.DisplayMetrics;
-
import android.view.LayoutInflater;
-
import android.view.View;
-
import android.view.ViewGroup;
-
import android.view.WindowManager;
-
import android.widget.ArrayAdapter;
-
import android.widget.TextView;
-
import com.xuliugen.weichat.MainActivity.Recorder;
-
publicclassRecoderAdapterextendsArrayAdapter<Recorder>{
-
privateContext mContext;
-
privateList<Recorder> mDatas;
-
privateint mMinItemWidth;//最小的item宽度
-
privateint mMaxItemWidth;//最大的item宽度
-
privateLayoutInflater mInflater;
-
publicRecoderAdapter(Context context,List<Recorder> datas){
-
super(context,-1, datas);
-
mContext = context;
-
mDatas = datas;
- //获取屏幕的宽度
-
WindowManager wm =(WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
-
DisplayMetrics outMetrics =newDisplayMetrics();
-
wm.getDefaultDisplay().getMetrics(outMetrics);
-
mMaxItemWidth =(int)(outMetrics.widthPixels *0.7f);
-
mMinItemWidth =(int)(outMetrics.widthPixels *0.15f);
-
mInflater =LayoutInflater.from(context);
- }
- /** * 定义一个ViewHolder */
-
privateclassViewHolder{
-
TextView seconds;// 时间
-
View length;// 长度
- }
- @Override
-
publicView getView(int position,View convertView,ViewGroup parent){
-
ViewHolder holder =null;
-
if(convertView ==null){
-
convertView = mInflater.inflate(R.layout.item_recoder, parent,false);
-
holder =newViewHolder();
-
holder.seconds =(TextView) convertView.findViewById(R.id.id_recoder_time);
-
holder.length = convertView.findViewById(R.id.id_recoder_lenght);
-
convertView.setTag(holder);
-
}else{
-
holder =(ViewHolder) convertView.getTag();
- }
-
holder.seconds.setText(Math.round(getItem(position).time)+"\"");
-
ViewGroup.LayoutParams lp = holder.length.getLayoutParams();
-
lp.width =(int)(mMinItemWidth +(mMaxItemWidth /60f)* getItem(position).time);
-
return convertView;
- }
- }
Android模仿微信语音聊天功能-IT蓝豹
原文:http://wuchengyi-1994.iteye.com/blog/2247487