首页 > 系统 > Android > 正文

Android仿微信语音聊天功能

2019-10-24 20:32:38
字体:
来源:转载
供稿:网友
这篇文章主要介绍了Android仿微信语音聊天功能,很实用,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
 

本文实例讲述了Android仿微信语音聊天功能代码。分享给大家供大家参考。具体如下:
项目效果如下:

Android仿微信语音聊天功能

Android仿微信语音聊天功能

Android仿微信语音聊天功能

具体代码如下:

AudioManager.java

 

package com.xuliugen.weichat;import java.io.File;import java.io.IOException;import java.util.UUID;import android.media.MediaRecorder;public class AudioManager { private MediaRecorder mMediaRecorder; private String mDir; private String mCurrentFilePath; private static AudioManager mInstance; private boolean isPrepare; 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 interface AudioStateListener {  void wellPrepared(); } public AudioStateListener mAudioStateListener; /**  * 回调方法  */ public void setOnAudioStateListener(AudioStateListener listener) {  mAudioStateListener = listener; } // 去准备 public void prepareAudio() {  try {   isPrepare = 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();   // 设置输出文件   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();  } } /**  * 随机生成文件的名称  */ private String generateFileName() {  return UUID.randomUUID().toString() + ".amr"; } public int getVoiceLevel(int maxlevel) {  if (isPrepare) {   try {    // mMediaRecorder.getMaxAmplitude() 1~32767    return maxlevel * mMediaRecorder.getMaxAmplitude() / 32768 + 1;   } catch (Exception e) {   }  }  return 1; } /**  * 释放资源  */ public void release() {  //mMediaRecorder.stop();  mMediaRecorder.reset();  mMediaRecorder = null; } /**  * 取消录音  */ public void cancel() {  release();  if (mCurrentFilePath != null) {   File file = new File(mCurrentFilePath);   file.delete();   mCurrentFilePath = null;  } } public String 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;public class AudioRecorderButton extends Button { 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 mCurrentState = STATE_NORMAL; // 当前的状态 private boolean isRecording = false;// 已经开始录音 private static final int DISTANCE_Y_CANCEL = 50; private DialogManager mDialogManager; private AudioManager mAudioManager; private float mTime; // 是否触发longClick private boolean mReady; 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 Runnable mGetVoiceLevelRunnable = new Runnable() {  public void run() {   while (isRecording) {    try {     Thread.sleep(100);     mTime += 0.1f;     mHandler.sendEmptyMessage(MSG_VOICE_CHANGED);    } catch (InterruptedException e) {     e.printStackTrace();    }   }  } }; private Handler mHandler = new Handler() {  @Override  public void handleMessage(Message msg) {   switch (msg.what) {   case MSG_AUDIO_PREPARED:    // 显示對話框在开始录音以后    mDialogManager.showRecordingDialog();    isRecording = true;    // 开启一个线程    new Thread(mGetVoiceLevelRunnable).start();    break;   case MSG_VOICE_CHANGED:    mDialogManager.updateVoiceLevel(mAudioManager.getVoiceLevel(7));    break;   case MSG_DIALOG_DIMISS:    mDialogManager.dimissDialog();    break;   }   super.handleMessage(msg);  } }; /**  * 以下2个方法是构造方法  */ public AudioRecorderButton(Context context, AttributeSet attrs) {  super(context, attrs);  mDialogManager = new DialogManager(context);  String dir = "/storage/sdcard0/my_weixin";  //String dir = Environment.getExternalStorageDirectory()+"/my_weixin";  mAudioManager = AudioManager.getInstance(dir);  mAudioManager.setOnAudioStateListener(new AudioStateListener() {   public void wellPrepared() {    mHandler.sendEmptyMessage(MSG_AUDIO_PREPARED);   }  });  // 由于这个类是button所以在构造方法中添加监听事件  setOnLongClickListener(new OnLongClickListener() {   public boolean onLongClick(View v) {    mReady = true;    mAudioManager.prepareAudio();    return false;   }  }); } public AudioRecorderButton(Context context) {  this(context, null); } /**  * 录音完成后的回调  */ public interface AudioFinishRecorderListener {  void onFinish(float seconds, String filePath); } private AudioFinishRecorderListener audioFinishRecorderListener; public void setAudioFinishRecorderListener(AudioFinishRecorderListener listener) {  audioFinishRecorderListener = listener; } /**  * 屏幕的触摸事件  */ @Override public boolean onTouchEvent(MotionEvent event) {  int action = event.getAction();  int x = (int) event.getX();// 获得x轴坐标  int y = (int) event.getY();// 获得y轴坐标  switch (action) {  case MotionEvent.ACTION_DOWN:   changeState(STATE_RECORDING);   break;  case MotionEvent.ACTION_MOVE:   if (isRecording) {    // 如果想要取消,根据x,y的坐标看是否需要取消    if (wantToCancle(x, y)) {     changeState(STATE_WANT_TO_CANCEL);    } else {     changeState(STATE_RECORDING);    }   }   break;  case MotionEvent.ACTION_UP:   if (!mReady) {    reset();    return super.onTouchEvent(event);   }   if (!isRecording || mTime < 0.6f) {    mDialogManager.tooShort();    mAudioManager.cancel();    mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DIMISS, 1000);// 延迟显示对话框   } else if (mCurrentState == STATE_RECORDING) { // 正在录音的时候,结束    mDialogManager.dimissDialog();    mAudioManager.release();    if (audioFinishRecorderListener != null) {     audioFinishRecorderListener.onFinish(mTime,mAudioManager.getCurrentFilePath());    }   } else if (mCurrentState == STATE_WANT_TO_CANCEL) { // 想要取消    mDialogManager.dimissDialog();    mAudioManager.cancel();   }   reset();   break;  }  return super.onTouchEvent(event); } /**  * 恢复状态及标志位  */ private void reset() {  isRecording = false;  mTime = 0;  mReady = false;  changeState(STATE_NORMAL); } private boolean wantToCancle(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 (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 *  */public class DialogManager { private AlertDialog.Builder builder; private ImageView mIcon; private ImageView mVoice; private TextView mLable; private Context mContext;  private AlertDialog dialog;//用于取消AlertDialog.Builder /**  * 构造方法 传入上下文  */ public DialogManager(Context context) {  this.mContext = context; } // 显示录音的对话框 public void showRecordingDialog() {  builder = new AlertDialog.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(); } public void 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("手指上滑,取消发送");  } } // 显示想取消的对话框 public void 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("松开手指,取消发送");  } } // 显示时间过短的对话框 public void 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("录音时间过短");  } } // 显示取消的对话框 public void dimissDialog() {  if(dialog != null && dialog.isShowing()){ //显示状态   dialog.dismiss();   dialog = null;  } } // 显示更新音量级别的对话框 public void 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;public class MainActivity extends Activity { private ListView mListView; private ArrayAdapter<Recorder> mAdapter; private List<Recorder> mDatas = new ArrayList<MainActivity.Recorder>(); private AudioRecorderButton mAudioRecorderButton; private View animView; @Override protected void 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(new AudioFinishRecorderListener() {   public void onFinish(float seconds, String filePath) {    Recorder recorder = new Recorder(seconds, filePath);    mDatas.add(recorder);    mAdapter.notifyDataSetChanged(); //通知更新的内容    mListView.setSelection(mDatas.size() - 1); //将lisview设置为最后一个   }  });  mAdapter = new RecoderAdapter(this, mDatas);  mListView.setAdapter(mAdapter);  //listView的item点击事件  mListView.setOnItemClickListener(new OnItemClickListener() {   public void 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,new MediaPlayer.OnCompletionListener() {      public void onCompletion(MediaPlayer mp) {       animView.setBackgroundResource(R.drawable.adj);      }     });   }  }); } @Override protected void onPause() {  super.onPause();  MediaManager.pause(); } @Override protected void onResume() {  super.onResume();  MediaManager.resume(); } @Override protected void onDestroy() {  super.onDestroy();  MediaManager.release(); } class Recorder {  float time;  String filePath;  public Recorder(float time, String filePath) {   super();   this.time = time;   this.filePath = filePath;  }  public float getTime() {   return time;  }  public void setTime(float time) {   this.time = time;  }  public String getFilePath() {   return filePath;  }  public void 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;public class MediaManager { private static MediaPlayer mMediaPlayer;  private static boolean isPause; /**  * 播放音乐  * @param filePath  * @param onCompletionListener  */ public static void playSound(String filePath,OnCompletionListener onCompletionListener) {  if (mMediaPlayer == null) {   mMediaPlayer = new MediaPlayer();   //设置一个error监听器   mMediaPlayer.setOnErrorListener(new OnErrorListener() {    public boolean onError(MediaPlayer arg0, int arg1, int arg2) {     mMediaPlayer.reset();     return false;    }   });  } else {   mMediaPlayer.reset();  }  try {   mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);   mMediaPlayer.setOnCompletionListener(onCompletionListener);   mMediaPlayer.setDataSource(filePath);   mMediaPlayer.prepare();   mMediaPlayer.start();  } catch (Exception e) {  } } /**  * 暂停播放  */ public static void pause() {  if (mMediaPlayer != null && mMediaPlayer.isPlaying()) { //正在播放的时候   mMediaPlayer.pause();   isPause = true;  } } /**  * 当前是isPause状态  */ public static void resume() {  if (mMediaPlayer != null && isPause) {    mMediaPlayer.start();   isPause = false;  } } /**  * 释放资源  */ public static void 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;public class RecoderAdapter extends ArrayAdapter<Recorder> { private Context mContext; private List<Recorder> mDatas; private int mMinItemWidth; //最小的item宽度 private int mMaxItemWidth; //最大的item宽度 private LayoutInflater mInflater; public RecoderAdapter(Context context, List<Recorder> datas) {  super(context, -1, datas);  mContext = context;  mDatas = datas;  //获取屏幕的宽度  WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);  DisplayMetrics outMetrics = new DisplayMetrics();  wm.getDefaultDisplay().getMetrics(outMetrics);  mMaxItemWidth = (int) (outMetrics.widthPixels * 0.7f);  mMinItemWidth = (int) (outMetrics.widthPixels * 0.15f);  mInflater = LayoutInflater.from(context); } /**  * 定义一个ViewHolder  */ private class ViewHolder {  TextView seconds; // 时间  View length; // 长度 } @Override public View getView(int position, View convertView, ViewGroup parent) {  ViewHolder holder = null;  if (convertView == null) {   convertView = mInflater.inflate(R.layout.item_recoder, parent,false);   holder = new ViewHolder();   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开发频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表