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

在本例子中, 我们需要用继承一个类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;
		}
	}
}


 

你可能感兴趣的:(Android 简单异步处理类------实现声音的录制及播放)