我有一个记录音频的AsyncTask。问题是,一旦我从UI线程调用cancel(true)
,isCancelled()
返回true
(就像它应该的那样),但doInBackground
函数一直在运行,如果我在AsyncTask上运行getStatus()
它返回 RUNNING ,onCancelled
方法都不会被称为nore onPostExecute
...
由于所有doInBackground
代码都放在while(!isCancelled())
内,因此该方法应在任务取消后结束......
while(!isCancelled())循环在我调用AsyncTask.cancel()后结束。我认为问题在于return null
没有被调用,这就是doInBackground
没有结束的原因......我可能错了......
代码:的
package Classes;
import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.AsyncTask;
import android.util.Log;
import com.appetizers.app.trytabs.Main2Activity;
/**
* Created by Alon on 09-Aug-16.
*/
public class RecordingTask2 extends AsyncTask<Void,Void,Void> {
AudioRecord record;
Context context;
int bufferSize;
int numSample=0;
private static int[] mSampleRates = new int[] { 8000, 11025, 22050, 44100 };
short[] audioBuffer;
public RecordingTask2(Context context) {
this.context = context;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
Log.d("RECTASK", "onPre");
record = findAudioRecord();
record.startRecording();
}
@Override
protected Void doInBackground(Void... params) {
audioBuffer = new short[bufferSize/2];
Log.d("RECTASK","before while");
while(!isCancelled())
{
//Log.d("RECTASK","isCancelled = "+isCancelled());
int numberOfShort = record.read(audioBuffer, 0, audioBuffer.length);
numSample +=numberOfShort;
}
Log.d("RECTASK", "after while\nisCancelled = "+isCancelled());
return null;
}
@Override
protected void onCancelled() {
super.onCancelled();
Log.d("RECTASK", "reached onCancel()");
end();
}
@Override
protected void onCancelled(Void aVoid) {
super.onCancelled(aVoid);
Log.d("RECTASK", "reached onCancelled(Void)");
end();
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Log.d("RECTASK", "reached onPost");
end();
}
private void end()
{
Log.d("RECTASK","reached end function");
record.stop();
record.release();
((Main2Activity)context).setNumOfSamples(numSample);
((Main2Activity)context).setSamples(audioBuffer);
}
public AudioRecord findAudioRecord() {
for (int rate : mSampleRates) {
for (short audioFormat : new short[] { AudioFormat.ENCODING_PCM_8BIT, AudioFormat.ENCODING_PCM_16BIT }) {
for (short channelConfig : new short[] { AudioFormat.CHANNEL_IN_MONO, AudioFormat.CHANNEL_IN_STEREO }) {
try {
Log.d("FINDAUDIO", "Attempting rate " + rate + "Hz, bits: " + audioFormat + ", channel: "
+ channelConfig);
bufferSize = AudioRecord.getMinBufferSize(rate, channelConfig, audioFormat);
if (bufferSize != AudioRecord.ERROR_BAD_VALUE) {
// check if we can instantiate and have a success
AudioRecord recorder = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, rate, channelConfig, audioFormat, bufferSize);
Log.d("FINDAUDIO", "AudioRecorder state = "+recorder.getState());
if (recorder.getState() == AudioRecord.STATE_INITIALIZED)
return recorder;
}
} catch (Exception e) {
Log.e("FINDAUDIO", rate + "Exception, keep trying.",e);
}
}
}
}
return null;
}
}
这是我在MainActivity类中调用和取消AsyncTask的部分代码
recordSlideBar.setDownRun(new Runnable() {
@Override
public void run() {
Log.d("MAINACT","onDown");
if(recTask==null || recTask.getStatus()!= AsyncTask.Status.RUNNING) {
recTask = new RecordingTask2(Main2Activity.this);
recTask.execute();
}
}
});
recordSlideBar.setUpRun(new Runnable() {
@Override
public void run() {
Log.d("MAINACT", "onUp");
recTask.cancel(true);
Log.d("MAINACT", "after cancel\nstatus = "+recTask.getStatus());
while(recTask.getStatus()!= AsyncTask.Status.FINISHED)
{
//waiting for task to end...
}
ShortBuffer shortBuffer = ShortBuffer.allocate(samples.length);
playTask = new PlayingTask(Main2Activity.this,shortBuffer,numOfSamples);
}
});
recordSlideBar
是我编写的自定义视图,其中包含onTouchListener,而recordSlideBar.setDownRun(Runnable)
将Runnable
设置为MotionEvent.ACTION_DOWN
,recordSlideBar.setUpRun(Runnable)
设置为{{ 1}}到Runnable
。
基本上,我创建AsyncTask并在调用MotionEvent.ACTION_UP
时执行它,并在调用ACTION_DOWN
时取消它...
我对整个音频捕获技术不熟悉,因此您可能会在我的代码中看到一些与此相关的错误。请记住,现在的问题是AsyncTask;)
编辑:取消任务后,这是调试器面板的打印屏幕。请注意,AsyncTask状态为 WAIT ,在“变量”标签中,ACTION_UP
为mCancelled
,true
为mStatus
Screen-shot: asynctask status=wait,cancelled=true,status=running
答案 0 :(得分:0)
可以在
中阻止read
功能
int numberOfShort = record.read(audioBuffer, 0, audioBuffer.length);
所以while(!isCancelled())
可能永远不会被调用。
您可以将Log.d()
放入while
以检查代码是否被阻止,例如
while(!isCancelled())
{
Log.d("RECTASK","start read");
int numberOfShort = record.read(audioBuffer, 0, audioBuffer.length);
numSample +=numberOfShort;
Log.d("RECTASK","end read");
}
答案 1 :(得分:0)
它被卡住了,因为正在使用的AudioRecord.read()
方法是一个阻塞调用,它在本机级而不是Java级阻塞。所以&#34;中断&#34;作为AsyncTask.cancel()
的一部分发送的将不起作用。不要使用此版本的read()
,而是使用带有readMode
参数的版本并将其设置为READ_NON_BLOCKING
。然后你的循环将需要处理部分读取(以及实际上对数据执行某些操作 - 现在它只是将其读入方法本地数组!)