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上了,有需要的朋友可以下载,看我上传的资源即可找到。


Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注