Android仿微信语音聊天功能
程序员文章站
2023-12-13 08:42:16
本文实例讲述了android仿微信语音聊天功能代码。分享给大家供大家参考。具体如下:
项目效果如下:
具体代码如下:
audiomanager.java...
本文实例讲述了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微信开发教程汇总》,欢迎大家学习阅读。
以上就是本文的全部内容,希望对大家的学习有所帮助。