您的位置:首页 > 移动开发 > Android开发

Android 简单异步处理类------实现声音的录制及播放

2012-02-23 23:00 501 查看
在本例子中, 我们需要用继承一个类AsyncTask以实现后台运行的效果 。

它可以跟线程一样适用于简单的异步处理,而且不需要借助线程和Handler即可实现。

AsyncTask有以下几个可以实现的几个方法:

onPreExecute();

该方法在开始进行后台操作前会被UI thread调用, 我们可以在该方法上做些初始化工作。

doInBackground(params...) ;

该方法在onPreExcute方法后执行, 并且会运行在后台中, 主要实现一些耗时的工作, 并可以使用publishProgress方法来指示当前的进度。

onProgressUpdate();

在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。

onPostExecute(Result),

在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用,后台的计算结果将通过该方法传递到UI thread.

为了正确的使用AsyncTask类,以下是几条必须遵守的准则:

  1) Task的实例必须在UI thread中创建

  2) execute方法必须在UI thread中调用

  3) 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法

  4) 该task只能被执行一次,否则多次调用时将会出现异常

      doInBackground方法和onPostExecute的参数必须对应,这两个参数在AsyncTask声明的泛型参数列表中指定,第一个为doInBackground接受的参数,第二个为显示进度的参数,第第三个为doInBackground返回和onPostExecute传入的参数。

 

接下来我们需要在该类中实例化两个重要的对象, 一个是AudioRecord, 用于录制声音。 而另一个是AudioTrack, 用于对声音的播放。

 

代码如下:

所需权限

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

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

 

public class SpeechTestActivity extends Activity
{
private Button mStartButton;
private Button mStopButton;
private Button mPlayButton;

private boolean isRecording = true; // 录制状态
private boolean isPlaying = false; // 播放状态
private File audioFile; // 声音文件
private RecordTask record; // 录制异步处理类
private PlayTask player; // 播放异步处理类

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

// 我们需要用到开始、停止、播放三个按钮
mStartButton = (Button) findViewById(R.id.btnStart);
mStopButton = (Button) findViewById(R.id.btnStop);
mPlayButton = (Button) findViewById(R.id.btnPlay);

mStartButton.setOnClickListener(btnListener);
mStopButton.setOnClickListener(btnListener);
mPlayButton.setOnClickListener(btnListener);

// 将缓存文件建立在SD卡根目录中, 用于储存记录的声音
File fpath = new File("sdcard/");
fpath.mkdirs(); // 创建一个目录

try
{
// 创建文件
audioFile = File.createTempFile("recording", ".pcm", fpath);
} catch (Exception e)
{
String strMsg = e.getMessage();
Log.i("i", strMsg);
}
}

private Button.OnClickListener btnListener = new Button.OnClickListener()
{
@Override
public void onClick(View v)
{
Button btn = (Button) v;
switch (btn.getId())
{
case R.id.btnStart:
{
record = new RecordTask();
record.execute();
}
break;
case R.id.btnPlay:
{
player = new PlayTask();
player.execute();
}
break;
case R.id.btnStop:
{
isRecording = false;
}
break;
default:
break;
}
}

};

// 该异步处理实现类录音的实现
public class RecordTask extends AsyncTask<Void, Integer, Void>
{

@Override
protected Void doInBackground(Void... params)
{
isRecording = true;
try
{
// 创建一个输入输出流
DataOutputStream dos = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream(audioFile)));

// 获取缓冲区大小
// 录制频率Hz、录制通道、录制编码格式
int bufferSize = AudioRecord.getMinBufferSize(8000,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT);

// 实例化一个录制对象
AudioRecord record = new AudioRecord(
MediaRecorder.AudioSource.MIC, 8000,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT, bufferSize);

// 缓冲区
short[] buffer = new short[bufferSize];

// 开始录制
record.startRecording();

int r = 0;
while (isRecording)
{
// 读出数据
int bufferReadResult = record
.read(buffer, 0, buffer.length);
for (int i = 0; i < bufferReadResult; i++)
{
// 写入流
dos.writeShort(buffer[i]);
}

// 为显示进度使用
publishProgress(new Integer(r));
r++;
}

record.stop();
dos.close();

} catch (Exception e)
{
// TODO: handle exception
}
return null;
}

protected void onProgressUpdate(Integer... progress)
{
// stateView.setText(progress[0].toString());
}
}

// 该异步处理实现类录音的播放
class PlayTask extends AsyncTask<Void, Integer, Void>
{

@Override
protected Void doInBackground(Void... params)
{
isPlaying = true;

int bufferSize = AudioTrack.getMinBufferSize(8000,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT);

// 缓冲区大小需要少于录制的大小
short[] buffer = new short[bufferSize / 4];

try
{
// 定义输入流,将音频写入到AudioTrack类中,实现播放
DataInputStream dis = new DataInputStream(
new BufferedInputStream(new FileInputStream(audioFile)));

// 实例化一个播放对象
AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC,
8000, AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT, bufferSize,
AudioTrack.MODE_STREAM);

// 开始播放
track.play();

// 由于AudioTrack播放的是流,所以,我们需要一边播放一边读取
while (isPlaying && dis.available() > 0)
{
int i = 0;
while (dis.available() > 0 && i < buffer.length)
{
buffer[i] = dis.readShort();
i++;
}
// 然后将数据写入到AudioTrack中
track.write(buffer, 0, buffer.length);
}

track.stop();
dis.close();
} catch (Exception e)
{
// TODO: handle exception
}

return null;
}
}
}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息