Android 仿微信语音识别

参考与:http://www.2cto.com/kf/201505/396842.html,这网站代码跑起来有问题,自己改动了一下,基本上没什么大问题

发现问题可以评论,我会回复的

先贴下效果图



1、三个布局文件

activity_main.xml
<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" >

    <ListView
        android: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>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <!-- minHeight消除主界面上的一些间距 -->

        <com.nickming.view.AudioRecordButton
            android: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>

        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#ccc" />
    </FrameLayout>

</LinearLayout>

dialog_manger.xml
<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" >

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <ImageView
            android:id="@+id/dialog_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/recorder"
            android:visibility="visible" />

        <ImageView
            android:id="@+id/dialog_voice"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/v1"
            android:visibility="visible" />
    </LinearLayout>

    <TextView
        android: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>

item_layout
<?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" >

    <ImageView
        android: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" />

    <FrameLayout
        android: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/show_anim01"
          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>

2.自定义的类
(1)DialogManger
package com.nickming.view;

import com.example.weixin_record.R;

import android.app.Dialog;
import android.content.Context;
import android.graphics.drawable.AnimationDrawable;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
/**
 * 
 * @ClassName:  DialogManager   
 * @Description:对话框管理类
 * @author:  张  维
 * @date:   2016-5-23 下午4:56:03   
 *
 */
public class DialogManager {

	/**
	 * 以下为dialog的初始化控件,包括其中的布局文件
	 */

	private Dialog mDialog;

	private ImageView mIcon;
	private ImageView mVoice;

	private TextView mLable;

	private Context mContext;

	public DialogManager(Context context) {
		mContext = context;
	}

	public void showRecordingDialog() {

		mDialog = 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);
		mVoice.setBackgroundResource(R.drawable.play02);
		AnimationDrawable drawable = (AnimationDrawable) mVoice
				.getBackground();
		drawable.start();
		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 stub
		if (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 timeShort() {
		// TODO Auto-generated method stub
		if (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.timeshort);
		}

	}

	// 隐藏dialog
	public void dimissDialog() {
		// TODO Auto-generated method stub

		if (mDialog != null && mDialog.isShowing()) {
			mDialog.dismiss();
			mDialog = null;
		}

	}

	public void updateVoiceLevel(int level) {
		// TODO Auto-generated method stub

		if (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);
		}

	}

}
(2)AudioRecordButton
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;
/**
 * 
 * @ClassName:  AudioRecordButton   
 * @Description:自定义的button按钮 
 * @author:  张  维
 * @date:   2016-5-23 下午2:13:20   
 *
 */
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()
				+ "/temp";
		mAudioManager = AudioManager.getInstance(dir);
		mAudioManager.setOnAudioStageListener(this);
       
		setOnLongClickListener(new OnLongClickListener() {

			@Override
			public boolean onLongClick(View v) {
				// TODO Auto-generated method
				mReady = true;
				mAudioManager.prepareAudio();
				return false;
			}
		});
		
	}
	
	/**
	 * 录音完成后的回调,回调给activiy,可以获得mtime和文件的路径
	 * @author nickming
	 *
	 */
	public interface AudioFinishRecorderListener{
		void onFinished(float mtime,String filePath);
	}
	
	private AudioFinishRecorderListener mListener;
	
	public void setAudioFinishRecorderListener(AudioFinishRecorderListener listener)
	{
		mListener=listener;
	}

	// 获取音量大小的runnable
	private Runnable mGetVoiceLevelRunnable = new Runnable() {

		@Override
		public void run() {
			// TODO Auto-generated method stub
			while (isRecording) {
				try {
					Thread.sleep(100);
					mTime += 0.1f;
					mhandler.sendEmptyMessage(MSG_VOICE_CHANGE);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.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的消息
	@Override
	public void wellPrepared() {
		// TODO Auto-generated method stub
		mhandler.sendEmptyMessage(MSG_AUDIO_PREPARED);
	}

	/**
	 * 直接复写这个监听函数
	 */
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		int 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事件,没有的话直接返回reset
			if (!mReady) {
				reset();
				return super.onTouchEvent(event);
			}
			// 如果按的时间太短,还没准备好或者时间录制太短,就离开了,则显示这个dialog
			if (!isRecording || mTime < 0.6f) {
				mDialogManager.timeShort();//取消对话框
				mAudioManager.cancel();
				mhandler.sendEmptyMessageDelayed(MSG_DIALOG_DIMISS, 1300);// 持续1.3s
			} else if (mCurrentState == STATE_RECORDING) {//正常录制结束

				mDialogManager.dimissDialog();
				
				mAudioManager.release();// release释放一个mediarecorder
				
				if (mListener!=null) {// 并且callbackActivity,保存录音
				
					mListener.onFinished(mTime, mAudioManager.getCurrentFilePath());
				}
				
				
				
				

			} else if (mCurrentState == STATE_WANT_TO_CANCEL) {
				// cancel
				mAudioManager.cancel();
				mDialogManager.dimissDialog();
			}
			reset();// 恢复标志位

			break;

		}

		return super.onTouchEvent(event);
	}

	/**
	 * 回复标志位以及状态
	 */
	private void reset() {
		// TODO Auto-generated method stub
		isRecording = false;
		changeState(STATE_NORMAL);
		mReady = false;
		mTime = 0;
	}

	private boolean wantToCancel(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 (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);
				// 取消
				mDialogManager.wantToCancel();
				break;

			}
		}

	}

	@Override
	public boolean onPreDraw() {
		return false;
	}

}
(3) MediaRecorder
package com.nickming.view;

import java.io.File;
import java.io.IOException;
import java.util.UUID;

import android.media.MediaRecorder;
/**
 * 
 * @ClassName:  AudioManager   
 * @Description: 录音的管理类(准备工作)
 * @author:  张  维
 * @date:   2016-5-23 下午2:10:35   
 *
 */
public class AudioManager {

	private MediaRecorder mRecorder;
	private String mDirString;
	private String mCurrentFilePath;

	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);
			//判断对象file是否存在
			if (!dir.exists()) {
				//创建此抽象路径指定的目录,包括所有必须但不存在的父目录。(及可以创建多级目录,无论是否存在父目录)
				dir.mkdirs();
			}

			String fileNameString = generalFileName();
			File file = new File(dir, fileNameString);

			mCurrentFilePath = file.getAbsolutePath();

			mRecorder = new MediaRecorder();
			// 设置输出文件
			mRecorder.setOutputFile(file.getAbsolutePath());
			// 设置meidaRecorder的音频源是麦克风
			mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
			// 设置文件音频的输出格式为amr
			mRecorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
			// 设置音频的编码格式为amr
			mRecorder.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 block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/**
	 * 随机生成文件的名称
	 * 
	 * @return
	 */
	private String generalFileName() {
		
        //UUID.randomUUID().toString()是javaJDK提供的一个自动生成主键的方法。
		return UUID.randomUUID().toString() + ".amr";
	}

	// 获得声音的大小
	public int getVoiceLevel(int maxLevel) {
		// mRecorder.getMaxAmplitude()这个是音频的振幅范围,值域是1-32767
		if (isPrepared) {
			try {
				// 取证+1,否则去不到7
				return maxLevel * mRecorder.getMaxAmplitude() / 32768 + 1;
			} catch (Exception e) {
				
			}
		}

		return 1;
	}

	// 释放资源
	public void release() {
		// 严格按照api流程进行
		mRecorder.stop();
		mRecorder.release();
		mRecorder = null;

	}

	// 取消,因为prepare时产生了一个文件,所以cancel方法应该要删除这个文件,
	// 这是与release的方法的区别
	public void cancel() {
		release();
		if (mCurrentFilePath != null) {
			File file = new File(mCurrentFilePath);
			file.delete();//删除文件
			mCurrentFilePath = null;
		}

	}

	public String getCurrentFilePath() {
		return mCurrentFilePath;
	}

}


3.调用的类
(1)RecorderAdapter   
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;
/**
 * 
 * @ClassName:  RecorderAdapter   
 * @Description:list的适配器 
 * @author:  张  维
 * @date:   2016-5-23 下午4:04:02   
 *
 */
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);
		
		inflater = 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);
	}

	@Override
	public 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;// 对话框长度
	}

}

(2) MediaManager  
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;
import android.util.Log;
/**
 * 
 * @ClassName:  MediaManager   
 * @Description:播放的管理类
 * @author:  张  维
 * @date:   2016-5-23 下午4:04:43   
 *
 */
public class MediaManager {


	private static MediaPlayer mPlayer;
	
	private static boolean isPause;

	public static  void playSound(String filePathString,
			OnCompletionListener onCompletionListener) {
		
		if (mPlayer==null) {
			mPlayer=new MediaPlayer();
			//保险起见,设置报错监听
			mPlayer.setOnErrorListener(new OnErrorListener() {
				
				@Override
				public boolean onError(MediaPlayer mp, int what, int extra) {
					Log.i("info", "");
					mPlayer.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) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.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;
		}
	}
}

(3) MainActivity
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.util.Log;
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>();

	@Override
	protected 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() {

			@Override
			public void onFinished(float seconds, String filePath) {
				// TODO Auto-generated method stub
				Recorder 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() {

			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				
				// 播放动画
				if (viewanim!=null) {//让第二个播放的时候第一个停止播放
					viewanim.setBackgroundResource(R.drawable.adj);
					viewanim=null;
				}
				viewanim = view.findViewById(R.id.show_anim01);
				viewanim.setBackgroundResource(R.drawable.play);
				AnimationDrawable drawable = (AnimationDrawable) viewanim
						.getBackground();
				drawable.start();

				// 播放音频
				Log.i("info", "position==="+position);
				MediaManager.playSound(mDatas.get(position).filePathString,
						new MediaPlayer.OnCompletionListener() {

							@Override
							public void onCompletion(MediaPlayer mp) {
							viewanim.setBackgroundResource(R.drawable.adj);

							}
						});
			}
		});
	}
	
	@Override
	protected void onPause() {
		// TODO Auto-generated method stub
		super.onPause();
		MediaManager.pause();
	}
	
	@Override
	protected void onResume() {
		// TODO Auto-generated method stub
		super.onResume();
		MediaManager.resume();
	}
	
	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		super.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;
		}

	}

}

要完整的Demo下载地址:
http://download.csdn.net/detail/zhang106209/9528686



  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现Android仿微信语音通话的效果,你可以按照以下步骤进行操作: 1. 首先,在styles.xml文件中定义一个自定义的对话框主题,可以参考引用\[1\]中的代码。这个主题可以设置对话框的背景透明、无边框、浮现在activity之上以及背景模糊显示等效果。 2. 在strings.xml文件中定义三个字符串资源,分别表示正常录音状态、录音中状态和取消发送状态。可以参考引用\[2\]中的代码。 3. 在布局文件中创建一个用于显示语音通话的界面,可以使用一个ImageView显示语音图标,一个TextView显示录音状态,以及一个Button用于开始和结束录音。 4. 在Activity中,根据用户的操作来改变TextView的文本内容,以及根据录音状态来改变ImageView的图标。 5. 使用MediaRecorder类来实现录音功能,可以在Button的点击事件中开始和结束录音。 6. 使用AudioManager类来控制音频的播放和停止,可以在Activity的生命周期方法中进行相应的操作。 通过以上步骤,你可以实现一个仿微信语音通话的效果。记得根据你的具体需求进行适当的修改和调整。 #### 引用[.reference_title] - *1* *2* [Android 仿微信实现语音聊天功能](https://blog.csdn.net/lhk147852369/article/details/78658055)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值