Android仿微信语音聊天demo
? ? ? ?其實我接觸android時間也不是很久,但是發現android遠遠比我們想象的要有趣并且復雜很多,所以還是要多花點時間來寫一寫這些demo例子,這個程序是我從慕課網上學來的,因為畢竟要自己手寫,才能體會到程序的完整性,所以我還是建議大家自己手寫代碼,大部分代碼我已經添加了注釋,如果有疑問,大家一起來討論討論。
效果圖
主布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context="com.example.weixin_record.MainActivity" ><ListViewandroid:id="@+id/listview"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:background="#ebebeb"android:divider="@null"android:dividerHeight="10dp" ></ListView><FrameLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content" ><!-- minHeight消除主界面上的一些間距 --><com.nickming.view.AudioRecordButtonandroid:id="@+id/recordButton"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginBottom="7dp"android:layout_marginLeft="50dp"android:layout_marginRight="50dp"android:layout_marginTop="6dp"android:background="@drawable/button_recordnormal"android:gravity="center"android:minHeight="0dp"android:padding="5dp"android:text="@string/normal"android:textColor="#727272" ></com.nickming.view.AudioRecordButton><Viewandroid:layout_width="match_parent"android:layout_height="1dp"android:background="#ccc" /></FrameLayout></LinearLayout>
listview的item布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="60dp"android:layout_marginTop="5dp" ><ImageViewandroid:id="@+id/item_icon"android:layout_width="40dp"android:layout_height="40dp"android:layout_alignParentRight="true"android:layout_centerVertical="true"android:layout_marginRight="5dp"android:src="@drawable/icon" /><FrameLayoutandroid:id="@+id/recorder_length"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_toLeftOf="@id/item_icon"android:background="@drawable/chatto_bg_focused" ><View android:id="@+id/id_recorder_anim"android:layout_width="25dp"android:layout_height="25dp"android:layout_gravity="center_vertical|right"android:background="@drawable/adj"/></FrameLayout><TextView android:id="@+id/recorder_time"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_marginRight="3dp"android:layout_toLeftOf="@id/recorder_length"android:text=""android:textColor="#ff777777"/></RelativeLayout>
dialog的布局樣式文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/dialog_loading_bg"android:gravity="center"android:orientation="vertical"android:padding="20dp"tools:context="com.example.weixin_record.MainActivity" ><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal" ><ImageViewandroid:id="@+id/dialog_icon"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/recorder"android:visibility="visible" /><ImageViewandroid:id="@+id/dialog_voice"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/v1"android:visibility="visible" /></LinearLayout><TextViewandroid:id="@+id/recorder_dialogtext"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="5dp"android:text="@string/shouzhishanghua"android:textColor="#ffffffff" /></LinearLayout>
新建文件夾drawable,并創立這些自定義資源文件
button加載時樣式的文件
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" ><solid android:color="#eeeeee" /> <!-- 背景色solid --><strokeandroid:width="1px"android:color="#9b9b9b" /> <!-- 邊框設置 --><corners android:radius="3dp" /> <!-- 轉角 --></shape>
button正常樣式文件
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" ><solid android:color="#ffffff" /> <!-- 背景色solid --><strokeandroid:width="1px"android:color="#9b9b9b" /> <!-- 邊框設置 --><corners android:radius="3dp" /> <!-- 轉角 --></shape>
播放時的幀動畫文件
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" ><itemandroid:drawable="@drawable/v_anim1"android:duration="300"></item><itemandroid:drawable="@drawable/v_anim2"android:duration="300"></item><itemandroid:drawable="@drawable/v_anim3"android:duration="300"></item></animation-list>
string.xml
<?xml version="1.0" encoding="utf-8"?>
<resources><string name="app_name">weixin_Record</string><string name="hello_world">Hello world!</string><string name="action_settings">Settings</string><string name="normal">按住 說話</string><string name="recording">松開 結束</string><string name="want_to_cancle">松開手指,取消發送</string><string name="shouzhishanghua">手指上滑,取消發送</string><string name="tooshort">錄音時間過短</string></resources>
style.xml,這個主要改變了對話框的樣式
<resources xmlns:android="http://schemas.android.com/apk/res/android"><!--Base application theme, dependent on API level. This theme is replacedby AppBaseTheme from res/values-vXX/styles.xml on newer devices.--><style name="AppBaseTheme" parent="android:Theme.Light"><!--Theme customizations available in newer API levels can go inres/values-vXX/styles.xml, while customizations related tobackward-compatibility can go here.--></style><!-- Application theme. --><style name="AppTheme" parent="AppBaseTheme"><!-- All customizations that are NOT specific to a particular API-level can go here. --></style><!-- 設置彈出窗口的屬性,frame疊加,isfloat是否浮動,tarnslucent是否半透明,dim是背景是否變暗 --><style name="Theme_audioDialog" parent="@android:style/Theme.Dialog"><item name="android:windowBackground">@android:color/transparent</item><item name="android:windowFrame">@null</item><item name="android:windowIsFloating">true</item><item name="android:windowIsTranslucent">true</item><item name="android:backgroundDimEnabled">false</item></style></resources>
對了,要記得在mainfest中添加幾個權限
<uses-permission android:name="android.permission.RECORD_AUDIO" />
? ? <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
? ? <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
現在來寫主要的幾個類
AudioRecordButton.class
package com.nickming.view;import com.example.weixin_record.R;
import com.example.weixin_record.R.string;
import com.nickming.view.AudioManager.AudioStageListener;import android.R.bool;
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;public class AudioRecordButton extends Button implements AudioStageListener {private static final int STATE_NORMAL = 1;private static final int STATE_RECORDING = 2;private static final int STATE_WANT_TO_CANCEL = 3;private static final int DISTANCE_Y_CANCEL = 50;private int mCurrentState = STATE_NORMAL;// 已經開始錄音private boolean isRecording = false;private DialogManager mDialogManager;private AudioManager mAudioManager;private float mTime = 0;// 是否觸發了onlongclick,準備好了private boolean mReady;/*** 先實現兩個參數的構造方法,布局會默認引用這個構造方法, 用一個 構造參數的構造方法來引用這個方法 * @param context*/public AudioRecordButton(Context context) {this(context, null);// TODO Auto-generated constructor stub}public AudioRecordButton(Context context, AttributeSet attrs) {super(context, attrs);mDialogManager = new DialogManager(getContext());// 這里沒有判斷儲存卡是否存在,有空要判斷String dir = Environment.getExternalStorageDirectory()+ "/nickming_recorder_audios";mAudioManager = AudioManager.getInstance(dir);mAudioManager.setOnAudioStageListener(this);setOnLongClickListener(new OnLongClickListener() {@Overridepublic boolean onLongClick(View v) {// TODO Auto-generated methodmReady = true;mAudioManager.prepareAudio();return false;}});// TODO Auto-generated constructor stub}/*** 錄音完成后的回調,回調給activiy,可以獲得mtime和文件的路徑* @author nickming**/public interface AudioFinishRecorderListener{void onFinished(float seconds,String filePath);}private AudioFinishRecorderListener mListener;public void setAudioFinishRecorderListener(AudioFinishRecorderListener listener){mListener=listener;}// 獲取音量大小的runnableprivate Runnable mGetVoiceLevelRunnable = new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubwhile (isRecording) {try {Thread.sleep(100);mTime += 0.1f;mhandler.sendEmptyMessage(MSG_VOICE_CHANGE);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}};// 準備三個常量private static final int MSG_AUDIO_PREPARED = 0X110;private static final int MSG_VOICE_CHANGE = 0X111;private static final int MSG_DIALOG_DIMISS = 0X112;private Handler mhandler = new Handler() {public void handleMessage(android.os.Message msg) {switch (msg.what) {case MSG_AUDIO_PREPARED:// 顯示應該是在audio end prepare之后回調mDialogManager.showRecordingDialog();isRecording = true;new Thread(mGetVoiceLevelRunnable).start();// 需要開啟一個線程來變換音量break;case MSG_VOICE_CHANGE:mDialogManager.updateVoiceLevel(mAudioManager.getVoiceLevel(7));break;case MSG_DIALOG_DIMISS:break;}};};// 在這里面發送一個handler的消息@Overridepublic void wellPrepared() {// TODO Auto-generated method stubmhandler.sendEmptyMessage(MSG_AUDIO_PREPARED);}/*** 直接復寫這個監聽函數*/@Overridepublic boolean onTouchEvent(MotionEvent event) {// TODO Auto-generated method stubint action = event.getAction();int x = (int) event.getX();int y = (int) event.getY();switch (action) {case MotionEvent.ACTION_DOWN:changeState(STATE_RECORDING);break;case MotionEvent.ACTION_MOVE:if (isRecording) {// 根據x,y來判斷用戶是否想要取消if (wantToCancel(x, y)) {changeState(STATE_WANT_TO_CANCEL);} else {changeState(STATE_RECORDING);}}break;case MotionEvent.ACTION_UP:// 首先判斷是否有觸發onlongclick事件,沒有的話直接返回resetif (!mReady) {reset();return super.onTouchEvent(event);}// 如果按的時間太短,還沒準備好或者時間錄制太短,就離開了,則顯示這個dialogif (!isRecording || mTime < 0.6f) {mDialogManager.tooShort();mAudioManager.cancel();mhandler.sendEmptyMessageDelayed(MSG_DIALOG_DIMISS, 1300);// 持續1.3s} else if (mCurrentState == STATE_RECORDING) {//正常錄制結束mDialogManager.dimissDialog();mAudioManager.release();// release釋放一個mediarecorderif (mListener!=null) {// 并且callbackActivity,保存錄音mListener.onFinished(mTime, mAudioManager.getCurrentFilePath());}} else if (mCurrentState == STATE_WANT_TO_CANCEL) {// cancelmAudioManager.cancel();mDialogManager.dimissDialog();}reset();// 恢復標志位break;}return super.onTouchEvent(event);}/*** 回復標志位以及狀態*/private void reset() {// TODO Auto-generated method stubisRecording = false;changeState(STATE_NORMAL);mReady = false;mTime = 0;}private boolean wantToCancel(int x, int y) {// TODO Auto-generated method stubif (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) {// TODO Auto-generated method stubif (mCurrentState != state) {mCurrentState = state;switch (mCurrentState) {case STATE_NORMAL:setBackgroundResource(R.drawable.button_recordnormal);setText(R.string.normal);break;case STATE_RECORDING:setBackgroundResource(R.drawable.button_recording);setText(R.string.recording);if (isRecording) {mDialogManager.recording();// 復寫dialog.recording();}break;case STATE_WANT_TO_CANCEL:setBackgroundResource(R.drawable.button_recording);setText(R.string.want_to_cancle);// dialog want to cancelmDialogManager.wantToCancel();break;}}}@Overridepublic boolean onPreDraw() {// TODO Auto-generated method stubreturn false;}}
對話框的manager
DialogManager.class
package com.nickming.view;import com.example.weixin_record.R;import android.app.Dialog;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;public class DialogManager {/*** 以下為dialog的初始化控件,包括其中的布局文件*/private Dialog mDialog;private ImageView mIcon;private ImageView mVoice;private TextView mLable;private Context mContext;public DialogManager(Context context) {// TODO Auto-generated constructor stubmContext = context;}public void showRecordingDialog() {// TODO Auto-generated method stubmDialog = new Dialog(mContext,R.style.Theme_audioDialog);// 用layoutinflater來引用布局LayoutInflater inflater = LayoutInflater.from(mContext);View view = inflater.inflate(R.layout.dialog_manager, null);mDialog.setContentView(view);mIcon = (ImageView) mDialog.findViewById(R.id.dialog_icon);mVoice = (ImageView) mDialog.findViewById(R.id.dialog_voice);mLable = (TextView) mDialog.findViewById(R.id.recorder_dialogtext);mDialog.show();}/*** 設置正在錄音時的dialog界面*/public void recording() {if (mDialog != null && mDialog.isShowing()) {mIcon.setVisibility(View.VISIBLE);mVoice.setVisibility(View.VISIBLE);mLable.setVisibility(View.VISIBLE);mIcon.setImageResource(R.drawable.recorder);mLable.setText(R.string.shouzhishanghua);}}/*** 取消界面*/public void wantToCancel() {// TODO Auto-generated method stubif (mDialog != null && mDialog.isShowing()) {mIcon.setVisibility(View.VISIBLE);mVoice.setVisibility(View.GONE);mLable.setVisibility(View.VISIBLE);mIcon.setImageResource(R.drawable.cancel);mLable.setText(R.string.want_to_cancle);}}// 時間過短public void tooShort() {// TODO Auto-generated method stubif (mDialog != null && mDialog.isShowing()) {mIcon.setVisibility(View.VISIBLE);mVoice.setVisibility(View.GONE);mLable.setVisibility(View.VISIBLE);mIcon.setImageResource(R.drawable.voice_to_short);mLable.setText(R.string.tooshort);}}// 隱藏dialogpublic void dimissDialog() {// TODO Auto-generated method stubif (mDialog != null && mDialog.isShowing()) {mDialog.dismiss();mDialog = null;}}public void updateVoiceLevel(int level) {// TODO Auto-generated method stubif (mDialog != null && mDialog.isShowing()) {//先不改變它的默認狀態
// mIcon.setVisibility(View.VISIBLE);
// mVoice.setVisibility(View.VISIBLE);
// mLable.setVisibility(View.VISIBLE);//通過level來找到圖片的id,也可以用switch來尋址,但是代碼可能會比較長int resId = mContext.getResources().getIdentifier("v" + level,"drawable", mContext.getPackageName());mVoice.setImageResource(resId);}}}
audioManager.class
package com.nickming.view;import java.io.File;
import java.io.IOException;
import java.util.UUID;import com.example.weixin_record.R.string;import android.media.MediaRecorder;public class AudioManager {private MediaRecorder mRecorder;private String mDirString;private String mCurrentFilePathString;private boolean isPrepared;// 是否準備好了/*** 單例化的方法 1 先聲明一個static 類型的變量a 2 在聲明默認的構造函數 3 再用public synchronized static* 類名 getInstance() { if(a==null) { a=new 類();} return a; } 或者用以下的方法*//*** 單例化這個類*/private static AudioManager mInstance;private AudioManager(String dir) {mDirString=dir;}public static AudioManager getInstance(String dir) {if (mInstance == null) {synchronized (AudioManager.class) {if (mInstance == null) {mInstance = new AudioManager(dir);}}}return mInstance;}/*** 回調函數,準備完畢,準備好后,button才會開始顯示錄音框* * @author nickming**/public interface AudioStageListener {void wellPrepared();}public AudioStageListener mListener;public void setOnAudioStageListener(AudioStageListener listener) {mListener = listener;}// 準備方法public void prepareAudio() {try {// 一開始應該是false的isPrepared = false;File dir = new File(mDirString);if (!dir.exists()) {dir.mkdirs();}String fileNameString = generalFileName();File file = new File(dir, fileNameString);mCurrentFilePathString = file.getAbsolutePath();mRecorder = new MediaRecorder();// 設置輸出文件mRecorder.setOutputFile(file.getAbsolutePath());// 設置meidaRecorder的音頻源是麥克風mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);// 設置文件音頻的輸出格式為amrmRecorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);// 設置音頻的編碼格式為amrmRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);// 嚴格遵守google官方api給出的mediaRecorder的狀態流程圖mRecorder.prepare();mRecorder.start();// 準備結束isPrepared = true;// 已經準備好了,可以錄制了if (mListener != null) {mListener.wellPrepared();}} catch (IllegalStateException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}/*** 隨機生成文件的名稱* * @return*/private String generalFileName() {// TODO Auto-generated method stubreturn UUID.randomUUID().toString() + ".amr";}// 獲得聲音的levelpublic int getVoiceLevel(int maxLevel) {// mRecorder.getMaxAmplitude()這個是音頻的振幅范圍,值域是1-32767if (isPrepared) {try {// 取證+1,否則去不到7return maxLevel * mRecorder.getMaxAmplitude() / 32768 + 1;} catch (Exception e) {// TODO Auto-generated catch block}}return 1;}// 釋放資源public void release() {// 嚴格按照api流程進行mRecorder.stop();mRecorder.release();mRecorder = null;}// 取消,因為prepare時產生了一個文件,所以cancel方法應該要刪除這個文件,// 這是與release的方法的區別public void cancel() {release();if (mCurrentFilePathString != null) {File file = new File(mCurrentFilePathString);file.delete();mCurrentFilePathString = null;}}public String getCurrentFilePath() {// TODO Auto-generated method stubreturn mCurrentFilePathString;}}
MediaManager.class
package com.example.weixin_record;import java.io.IOException;import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;public class MediaManager {private static MediaPlayer mPlayer;private static boolean isPause;public static void playSound(String filePathString,OnCompletionListener onCompletionListener) {// TODO Auto-generated method stubif (mPlayer==null) {mPlayer=new MediaPlayer();//保險起見,設置報錯監聽mPlayer.setOnErrorListener(new OnErrorListener() {@Overridepublic boolean onError(MediaPlayer mp, int what, int extra) {// TODO Auto-generated method stubmPlayer.reset();return false;}});}else {mPlayer.reset();//就回復}try {mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);mPlayer.setOnCompletionListener(onCompletionListener);mPlayer.setDataSource(filePathString);mPlayer.prepare();mPlayer.start();} catch (IllegalArgumentException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (SecurityException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalStateException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}//停止函數public static void pause(){if (mPlayer!=null&&mPlayer.isPlaying()) {mPlayer.pause();isPause=true;}}//繼續public static void resume(){if (mPlayer!=null&&isPause) {mPlayer.start();isPause=false;}}public static void release(){if (mPlayer!=null) {mPlayer.release();mPlayer=null;}}
}
RecorderAdapter.class
package com.example.weixin_record;import java.util.List;import com.example.weixin_record.MainActivity.Recorder;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;public class RecorderAdapter extends ArrayAdapter<Recorder> {private LayoutInflater inflater;private int mMinItemWith;// 設置對話框的最大寬度和最小寬度private int mMaxItemWith;public RecorderAdapter(Context context, List<Recorder> dataList) {super(context, -1, dataList);// TODO Auto-generated constructor stubinflater = LayoutInflater.from(context);// 獲取系統寬度WindowManager wManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);DisplayMetrics outMetrics = new DisplayMetrics();wManager.getDefaultDisplay().getMetrics(outMetrics);mMaxItemWith = (int) (outMetrics.widthPixels * 0.7f);mMinItemWith = (int) (outMetrics.widthPixels * 0.15f);}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ViewHolder viewHolder = null;if (convertView == null) {convertView = inflater.inflate(R.layout.item_layout, parent, false);viewHolder=new ViewHolder();viewHolder.seconds=(TextView) convertView.findViewById(R.id.recorder_time);viewHolder.length=convertView.findViewById(R.id.recorder_length);convertView.setTag(viewHolder);}else {viewHolder=(ViewHolder) convertView.getTag();}viewHolder.seconds.setText(Math.round(getItem(position).time)+"\"");ViewGroup.LayoutParams lParams=viewHolder.length.getLayoutParams();lParams.width=(int) (mMinItemWith+mMaxItemWith/60f*getItem(position).time);viewHolder.length.setLayoutParams(lParams);return convertView;}class ViewHolder {TextView seconds;// 時間View length;// 對話框長度}}
MainActivity.class
package com.example.weixin_record;import java.util.ArrayList;
import java.util.List;import com.nickming.view.AudioRecordButton;
import com.nickming.view.AudioRecordButton.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.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;public class MainActivity extends Activity {AudioRecordButton button;private ListView mlistview;private ArrayAdapter<Recorder> mAdapter;private View viewanim;private List<Recorder> mDatas = new ArrayList<MainActivity.Recorder>();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mlistview = (ListView) findViewById(R.id.listview);button = (AudioRecordButton) findViewById(R.id.recordButton);button.setAudioFinishRecorderListener(new AudioFinishRecorderListener() {@Overridepublic void onFinished(float seconds, String filePath) {// TODO Auto-generated method stubRecorder recorder = new Recorder(seconds, filePath);mDatas.add(recorder);mAdapter.notifyDataSetChanged();mlistview.setSelection(mDatas.size() - 1);}});mAdapter = new RecorderAdapter(this, mDatas);mlistview.setAdapter(mAdapter);mlistview.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view,int position, long id) {// TODO Auto-generated method stub// 播放動畫if (viewanim!=null) {//讓第二個播放的時候第一個停止播放viewanim.setBackgroundResource(R.id.id_recorder_anim);viewanim=null;}viewanim = view.findViewById(R.id.id_recorder_anim);viewanim.setBackgroundResource(R.drawable.play);AnimationDrawable drawable = (AnimationDrawable) viewanim.getBackground();drawable.start();// 播放音頻MediaManager.playSound(mDatas.get(position).filePathString,new MediaPlayer.OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp) {viewanim.setBackgroundResource(R.id.id_recorder_anim);}});}});}@Overrideprotected void onPause() {// TODO Auto-generated method stubsuper.onPause();MediaManager.pause();}@Overrideprotected void onResume() {// TODO Auto-generated method stubsuper.onResume();MediaManager.resume();}@Overrideprotected void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();MediaManager.release();}class Recorder {float time;String filePathString;public Recorder(float time, String filePathString) {super();this.time = time;this.filePathString = filePathString;}public float getTime() {return time;}public void setTime(float time) {this.time = time;}public String getFilePathString() {return filePathString;}public void setFilePathString(String filePathString) {this.filePathString = filePathString;}}}
主要就是這幾個類了,另外工程我已經上傳到了csdn上了,有需要的朋友可以下載,看我上傳的資源即可找到。
總結
以上是生活随笔為你收集整理的Android仿微信语音聊天demo的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 201609-5 祭坛
- 下一篇: 201403-5 任务调度