当前位置: 移动技术网 > 移动技术>移动开发>Android > Android仿微信语音聊天功能

Android仿微信语音聊天功能

2019年07月24日  | 移动技术网移动技术  | 我要评论

本文实例讲述了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微信开发教程汇总》,欢迎大家学习阅读。

以上就是本文的全部内容,希望对大家的学习有所帮助。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网