0
点赞
收藏
分享

微信扫一扫

Android 多媒体之实现语音聊天界面


一、概述:

1、需要实现的功能:
1)语音的录制
2)按钮状态的切换
3)对话框状态的切换
4)聊天界面的切换

2、所用到的技术:
1)核心技术:根据按钮的onTouchEvent实现down、move、up触发的事件
down时:

```
changeState(state_record)
LongClick->AudioManager.prepare()->end parepared -> DialogManager.showDialog(recording);
```

move时:

```
if(wantCancel(x,y){
DialogManager.showDialog(want_to_cancel);
changeState(state_want_to_cancel)
}else{
DialogManager.showDialog(record);
changeState(state_record)
}
```

up时:

```
if(wantCancel == curState){
AudioManager.cancel();
}else if(state_recode == curState){
AudioManager.release();
callbackToActivity(url,time);
}
```

3、主要的三个类存在的状态:
1)AudioRecorderButton类(录音按钮):
State:STATE_NORMAL【正常状态】、STATE_RECORDERING【正在录音的状态】、STATE_WANT_TO_CALCEL【想要放弃录音的装填】;
(2)AudioDialogManage类(录音过程中的提示对话框):
Style:RECORDERING【正在录音】、WANT_TO_CANCEL【取消提示对话框】、TOO_SHAORT【录音时间过短提醒对话框】;
(3)AudioManage类(控制录音):
prepare()(end prepare-—》callback)【去录音】, cancel()【取消录音】, release()【正常结束】(-—》callbackToActivity), getVoiceLevel()【获得音量大小】;

4、效果图:

Android 多媒体之实现语音聊天界面_多媒体

5、重点说明:
DialogHelper类里使用了context 是Activity级别的,而Dialog是application级别的,
如果使用了单例模式,在其它Activity里,Dialog就不能释放,就会造成内存泄漏,产生anr异常

二、搭建基本框架:

1、创建按钮:

/**
* @描述 TODO
* @项目名称 App_imooc
* @包名 com.android.imooc.chat
* @类名 RecordButton
* @author chenlin
* @date 2013年6月13日 下午10:42:50
*/

public class RecordButton extends Button {

public RecordButton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public RecordButton(Context context) {
this(context, null);
}

public RecordButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}

}

2、创建布局,把按钮添加到布局里

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

<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.android.imooc.chat.RecordButton
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.android.imooc.chat.RecordButton>

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

</LinearLayout>

3、创建主页:

/**
* @描述 聊天布局
* @项目名称 App_imooc
* @包名 com.android.imooc.chat
* @类名 ChatActivity
* @author chenlin
* @date 2013年6月13日 下午10:31:59
* @version 1.0
*/

public class ChatActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
}
}

三、按钮的基本功能实现:

1、添加状态

//按住说话状态
private static final int STATE_NORMAL = 0x00;
//正在录音状态
private static final int STATE_RECORDING = 0x01;
//准备取消状态
private static final int STATE_WANT_TO_CANCEL = 0x02;
//当前状态
private int curState = STATE_NORMAL;
//表示已经录音
private boolean isRecording;

2、添加ontouchEvent

@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
changeState(STATE_RECORDING);
break;
case MotionEvent.ACTION_MOVE:
if (isRecording) {
//根据坐标判断是否要取消
if (wantToCancel(x, y)) {
changeState(STATE_WANT_TO_CANCEL);
}else {
changeState(STATE_RECORDING);
}
}

break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (curState == STATE_RECORDING) {

}else if (curState == STATE_WANT_TO_CANCEL) {

}

//恢复状态等信息
reset();
break;

default:
break;
}
return true;
}

private void reset() {
isRecording = false;
}

private boolean wantToCancel(int x, int y) {
// TODO Auto-generated method stub
return false;
}

private void changeState(int stateRecording) {
// TODO Auto-generated method stub

}

3、实现changeState方法,在这个方法里,根据传入的状态,设置按钮的颜色,背景色等

private void changeState(int state) {
if (mCurState != state) {
mCurState = state;
}
switch (state) {
case STATE_NORMAL:
setBackgroundResource(R.drawable.button_recordnormal);
setText(R.string.chat_normal);
break;
case STATE_RECORDING:
setBackgroundResource(R.drawable.button_recording);
setText(R.string.chat_recording);
break;
case STATE_WANT_TO_CANCEL:
setBackgroundResource(R.drawable.button_recording);
setText(R.string.chat_want_to_cancel);
break;
default:
break;
}
}

4、实现判断是否要取消状态,根据手指的移到范围

private boolean wantToCancel(int x, int y) {
//如果手指不在按钮的x轴范围内
if (x < 0 || x > getWidth()) {
return true;
}
//getHeight是按钮的高度
if (y < -DISTANCE_Y_CANCEL || y > getHeight() + DISTANCE_Y_CANCEL) {
return true;
}

return false;
}

四、对话框的实现:

1、从效果图可发现,对话框里有声音图片,背景图片,文字等
所以要定义

public class DialogHelper {
private Dialog mDialog;
private ImageView mIcon;
private ImageView mVoice;
private TextView mLabel;
private Context mContext;

public DialogHelper(Context context){
this.mContext = context;
}
}

2、需要实现的方法:

/**
* 显示
*/
public void showDialog(){

}
/**
* 准备关闭
*/
public void wantToCancel(){

}
/**
* 时间太短提示
*/
public void tooShort(){

}
/**
* 关闭
*/
public void dimiss(){

}
/**
* 更新声音的大小
* @param level
*/
public void updateVoiceLevel(int level){

}

3、实现showDialog方法
1)首先得定义布局文件

<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/chat_moveUp"
android:textColor="#ffffffff" />

</LinearLayout>

如图:

Android 多媒体之实现语音聊天界面_多媒体_02

2)定义样式:

<!-- 设置弹出窗口的属性,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>

3)初始化、加载布局并添加样式,显示对话框

/**
* 显示
*/
public void showDialog(){
mDialog = new Dialog(mContext, R.style.Theme_audioDialog);
LayoutInflater layoutInflater = LayoutInflater.from(mContext);
View view = layoutInflater.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);
mLabel = (TextView) mDialog.findViewById(R.id.recorder_dialogtext);

mDialog.show();
}

4、实现recording、wantToCancel,tooShort与dimiss方法
最主要的就是dialog的view的操作,显示隐藏等

/**
* 录音
*/
public void recording(){
if (mDialog != null && mDialog.isShowing()) {
mIcon.setVisibility(View.VISIBLE);
mVoice.setVisibility(View.VISIBLE);
mLabel.setVisibility(View.VISIBLE);

mIcon.setImageResource(R.drawable.recorder);
mLabel.setText(mContext.getResources().getString(R.string.chat_moveUp));
}
}
/**
* 准备关闭
*/
public void wantToCancel(){
if (mDialog != null && mDialog.isShowing()) {
mIcon.setVisibility(View.VISIBLE);
mVoice.setVisibility(View.GONE);
mLabel.setVisibility(View.VISIBLE);

mIcon.setImageResource(R.drawable.cancel);
mLabel.setText(mContext.getResources().getString(R.string.chat_release));
}
}
/**
* 时间太短提示
*/
public void tooShort(){
if (mDialog != null && mDialog.isShowing()) {
mIcon.setVisibility(View.VISIBLE);
mVoice.setVisibility(View.GONE);
mLabel.setVisibility(View.VISIBLE);

mIcon.setImageResource(R.drawable.voice_to_short);
mLabel.setText(mContext.getResources().getString(R.string.chat_tooShort));
}
}
/**
* 关闭
*/
public void dimiss(){
if (mDialog != null && mDialog.isShowing()) {
mDialog.dismiss();
mDialog = null;
}
}

5、更新声音的大小

Android 多媒体之实现语音聊天界面_多媒体_03


如图,有七张图片,如何动态获取图片id呢?

int resId = mContext.getResources().getIdentifier(“v” + level, “drawable”, mContext.getPackageName());

/**
* 更新声音的大小
* @param level
*/
public void updateVoiceLevel(int level){
if (mDialog != null && mDialog.isShowing()) {
mIcon.setVisibility(View.VISIBLE);
mVoice.setVisibility(View.VISIBLE);
mLabel.setVisibility(View.VISIBLE);

int resId = mContext.getResources().getIdentifier("v" + level, "drawable", mContext.getPackageName());
mVoice.setImageResource(resId);
}
}

6、在RecordButton里使用DialogHelper

public RecordButton(Context context, AttributeSet attrs) {
super(context, attrs);
mdDialogHelper = new DialogHelper(context);
setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
Logger.i(TAG, "onLongClick");
isRecording = true;
mdDialogHelper.showDialog();
return false;
}
});
}


@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 按下时,开始播放
changeState(STATE_RECORDING);
break;
case MotionEvent.ACTION_MOVE:
if (isRecording) {
// 根据坐标判断是否要取消
if (wantToCancel(x, y)) {
changeState(STATE_WANT_TO_CANCEL);
} else {
changeState(STATE_RECORDING);
}
}

break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (mCurState == STATE_RECORDING) {
mdDialogHelper.dimiss();
} else if (mCurState == STATE_WANT_TO_CANCEL) {
mdDialogHelper.dimiss();
}

// 恢复状态等信息
reset();
break;

default:
break;
}
return super.onTouchEvent(event);
}

五、声音处理

1、添加权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />

2、创建声音帮助类,初步实现:

/**
* @描述 声音处理类,使用单例模式
* @项目名称 App_imooc
* @包名 com.android.imooc.chat
* @类名 AudioHelper
* @author chenlin
* @date 2013年6月15日 下午9:51:21
*/

public class AudioHelper {
private MediaRecorder mRecorder;
private String mDir;
private String mCurrentFilePaht;

//单例模式--------------------------
private static AudioHelper instance;
private AudioHelper(){}
public static AudioHelper getInstance(){
if (instance == null) {
synchronized (AudioHelper.class) {
if (instance == null) {
instance = new AudioHelper();
}
}
}
return instance;
}

//回调函数--------------------------
public interface AudioStateListener {
void onPrepared();
}
private AudioStateListener mListener;
public void setAudioStateListener(AudioStateListener listener){
this.mListener = listener;
}

/**
* 获得声音的等级
* @return
*/
public int getVoiceLevel(){
return 1;
}
/**
* 初始化
*/
public void prepare(){

}

public void record(){

}

public void cancel(){

}

}

3、编写方法prepare:

MediaRecorder:​​http://developer.android.com/reference/android/media/MediaRecorder.html​​

MediaRecorder状态转换图:

Android 多媒体之实现语音聊天界面_聊天_04

/**
* 初始化
*/
public void prepare() {
// 找到文件路径
File dir = new File(mDir);
if (!dir.exists()) {
dir.mkdirs();
}
String fileName = generateFileName();
File file = new File(dir, fileName);
// 初始化MediaRecorder
mMediaRecorder = new MediaRecorder();
// 设置各种
mMediaRecorder.setOutputFile(file.getAbsolutePath());
mMediaRecorder.setOutputFile(file.getAbsolutePath());// 设置输出文件
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);// 设置MediaRecorder的音频源为麦克风
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);// 设置音频的格式
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);// 设置音频的编码为AMR_NB
// prepare
try {
mMediaRecorder.prepare();
} catch (IllegalStateException e) {
throw new RuntimeException("MediaRecorder 参数错误 " + e.getMessage());
} catch (IOException e) {
throw new RuntimeException("MediaRecorder 不能启动 " + e.getMessage());
}

mMediaRecorder.start();
isPrepared = true;

if (mListener != null) {
mListener.onPrepared();
}

}

4、其他三种方法:

/**
* 获得声音的等级
*
* @return
*/
public int getVoiceLevel(int maxLevel) {
if (isPrepared) {
try {
// getMaxAmplitude(): 1 - 32767
// mMediaRecorder.getMaxAmplitude() / 32768 : 0 - 1;
return (int) (maxLevel * mMediaRecorder.getMaxAmplitude() / 32768 + 0.5f);
} catch (IllegalStateException e) {
throw new RuntimeException("不能获得声音的振幅 " + e.getMessage());
}
}
return 1;
}

public void release() {
if (mMediaRecorder != null) {
mMediaRecorder.stop();
mMediaRecorder.release();
mMediaRecorder = null;
isPrepared = false;
}
}

public void cancel() {
release();
if (mCurrentFilePath != null) {
File file = new File(mCurrentFilePath);
if (file.exists()) {
file.delete();
}
}
mCurrentFilePath = null;
}

六、实现界面

1、创建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" >

<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/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>

2、完善主页:

package com.android.imooc.chat;

import java.util.ArrayList;
import java.util.List;

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;

import com.android.imooc.R;
import com.android.imooc.chat.RecordButton.AudioFinishRecordListener;

/**
* @描述 聊天布局
* @项目名称 App_imooc
* @包名 com.android.imooc.chat
* @类名 ChatActivity
* @author chenlin
* @date 2013年6月13日 下午10:31:59
* @version 1.0
*/

public class ChatActivity extends Activity {
private RecordButton mBtnRecord;

private ListView mlistview;
private ArrayAdapter<Recorder> mAdapter;
private View mView;
private List<Recorder> mDatas = new ArrayList<Recorder>();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);

mlistview = (ListView) findViewById(R.id.listview);
mAdapter = new RecorderAdapter(this, mDatas);
mlistview.setAdapter(mAdapter);

mBtnRecord = (RecordButton) findViewById(R.id.recordButton);

initEvents();


}

private void initEvents() {
mlistview.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//如果在播放第二动画时,判断原来的动画如果正在播放,就停止
if (mView != null) {
mView.setBackgroundResource(R.drawable.adj);
mView = null;
}
mView = findViewById(R.id.id_recorder_anim);
mView.setBackgroundResource(R.drawable.play_sound);
AnimationDrawable drawable = (AnimationDrawable) mView.getBackground();
drawable.start();

//开始播放声音
MediaHelper.playSound(mDatas.get(position).filePath,new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
mView.setBackgroundResource(R.drawable.adj);
}
});
}
});
mBtnRecord.setAudioFinishRecordListener(new AudioFinishRecordListener() {
@Override
public void onFinish(float second, String path) {
Recorder recorder = new Recorder(second, path);
mDatas.add(recorder);
mAdapter.notifyDataSetChanged();
mlistview.setSelection(mDatas.size() - 1);
}

});

}

@Override
protected void onResume() {
MediaHelper.resume();
super.onResume();
}

@Override
protected void onPause() {
MediaHelper.pause();
super.onPause();
}

@Override
protected void onDestroy() {
MediaHelper.release();
super.onDestroy();
}
}

3、实现mediaplayer

package com.android.imooc.chat;

import java.io.IOException;

import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;

/**
* @描述 声音控制类
* @项目名称 App_imooc
* @包名 com.android.imooc.chat
* @类名 MediaHelper
* @author chenlin
* @date 2013年6月17日 下午10:46:01
* @version 1.0
*/

public class MediaHelper {
private static MediaPlayer mPlayer;
private static boolean isPause = false;

public static void playSound(String filePath, OnCompletionListener listener) {
if (mPlayer == null) {
mPlayer = new MediaPlayer();
} else {
mPlayer.reset();
}
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mPlayer.setOnCompletionListener(listener);
mPlayer.setOnErrorListener(new OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
mPlayer.reset();
return false;
}
});
try {
mPlayer.setDataSource(filePath);
mPlayer.prepare();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
throw new RuntimeException("读取文件异常:" + e.getMessage());
}
mPlayer.start();
isPause = false;
}

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;
}
}

}

4、控制类recordButton全部代码

/**
* @描述 TODO
* @项目名称 App_imooc
* @包名 com.android.imooc.chat
* @类名 RecordButton
* @author chenlin
* @date 2013年6月13日 下午10:42:50
*/

public class RecordButton extends Button implements AudioStateListener {
private static final String TAG = "RecordButton";
//手指向上移动的距离50,如果超过,说明要cancel
private static final int DISTANCE_Y_CANCEL = 50;
// 按住说话状态
private static final int STATE_NORMAL = 0x00;
// 正在录音状态
private static final int STATE_RECORDING = 0x01;
// 准备取消状态
private static final int STATE_WANT_TO_CANCEL = 0x02;

// 当前状态
private int mCurState = STATE_NORMAL;
// 表示已经录音
private boolean isRecording;
//是否是长按了
private boolean isLongClick;

private DialogHelper mdDialogHelper;
private AudioHelper mAudioHelper;

//--录音完成回调------------------------------------------
public interface AudioFinishRecordListener {
void onFinish(float second, String path);
}

private AudioFinishRecordListener mListener;

public void setAudioFinishRecordListener(AudioFinishRecordListener listener) {
this.mListener = listener;
}

public RecordButton(Context context) {
this(context, null);
}
public RecordButton(Context context, AttributeSet attrs) {
super(context, attrs);
mdDialogHelper = new DialogHelper(context);
String dir = Environment.getExternalStorageDirectory() + File.separator + "chat";
mAudioHelper = AudioHelper.getInstance(dir);
mAudioHelper.setAudioStateListener(this);

setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
isLongClick = true;
mAudioHelper.prepare();
return false;
}
});

}

@Override
public void onPrepared() {
mHandler.sendEmptyMessage(MSG_AUDIO_PREPARED);
}

private Runnable mGetVoiceLevelRunnable = new Runnable() {
@Override
public void run() {
while(isRecording){
//SystemClock.sleep(100);
Logger.i(TAG, "run ========" );
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//每个0.1秒更新声音s
mTime += 0.1f;
mHandler.sendEmptyMessage(MSG_VOICE_CHANGED);
}

}
};

private static final int MSG_AUDIO_PREPARED = 0x11;//准备录制声音
private static final int MSG_VOICE_CHANGED = 0x12;//声音改变
private static final int MSG_DIALOG_DIMISS = 0x13;//对话框消失
private float mTime = 0;
private Handler mHandler = new Handler(){
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case MSG_AUDIO_PREPARED:
isRecording = true;
//显示声音对话框
mdDialogHelper.showDialog();
//开启线程获取音量
new Thread(mGetVoiceLevelRunnable).start();
break;
case MSG_VOICE_CHANGED:
int level = mAudioHelper.getVoiceLevel(7);
Logger.i(TAG, "level ========" + level);
//在对话框里更新声音的大小
mdDialogHelper.updateVoiceLevel(level);
break;
case MSG_DIALOG_DIMISS:
mdDialogHelper.dimiss();
break;

default:
break;
}
}
};



@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 按下时,开始播放
changeState(STATE_RECORDING);
break;
case MotionEvent.ACTION_MOVE:
if (isRecording) {
// 根据坐标判断是否要取消
if (wantToCancel(x, y)) {
changeState(STATE_WANT_TO_CANCEL);
} else {
changeState(STATE_RECORDING);
}
}

break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
//如果没有长按
if (!isLongClick) {
reset();
return super.onTouchEvent(event);
}
//如果没有录制
if (!isRecording || mTime < 0.6f) {
//显示按的时间太短
mdDialogHelper.tooShort();
//关闭录制
mAudioHelper.cancel();
//发送信息关闭资源
mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DIMISS, 1300);
} else if (mCurState == STATE_RECORDING) {
mdDialogHelper.dimiss();
if (mListener != null) {
mListener.onFinish(mTime, mAudioHelper.getFilePath());
}
mAudioHelper.release();

} else if (mCurState == STATE_WANT_TO_CANCEL) {
mdDialogHelper.dimiss();
mAudioHelper.cancel();
}


// 恢复状态等信息
reset();
break;

default:
break;
}
return super.onTouchEvent(event);
}

private void reset() {
isRecording = false;
changeState(STATE_NORMAL);
mTime = 0;
isLongClick = false;
}

private boolean wantToCancel(int x, int y) {
//如果手指不在按钮的x轴范围内
if (x < 0 || x > getWidth()) {
return true;
}
//getHeight是按钮的高度
if (y < -DISTANCE_Y_CANCEL || y > getHeight() + DISTANCE_Y_CANCEL) {
return true;
}

return false;
}

private void changeState(int state) {
if (mCurState != state) {
mCurState = state;
}
switch (state) {
case STATE_NORMAL:
setBackgroundResource(R.drawable.button_recordnormal);
setText(R.string.chat_normal);
break;
case STATE_RECORDING:
setBackgroundResource(R.drawable.button_recording);
setText(R.string.chat_recording);
if (isRecording) {
mdDialogHelper.recording();
}
break;
case STATE_WANT_TO_CANCEL:
setBackgroundResource(R.drawable.button_recording);
setText(R.string.chat_want_to_cancel);
mdDialogHelper.wantToCancel();
break;
default:
break;
}
}



}

七、源码下载:

———————————————————————
(java 架构师全套教程,共760G, 让你从零到架构师,每月轻松拿3万)

01.高级架构师四十二个阶段高
02.Java高级系统培训架构课程148课时
03.Java高级互联网架构师课程
04.Java互联网架构Netty、Nio、Mina等-视频教程
05.Java高级架构设计2016整理-视频教程
06.架构师基础、高级片
07.Java架构师必修linux运维系列课程
08.Java高级系统培训架构课程116课时
(送:hadoop系列教程,java设计模式与数据结构, Spring Cloud微服务, SpringBoot入门)
——————————————————————–


举报

相关推荐

0 条评论