AsyncTask isCancelled()返回true但是doInBackground没有结束

时间:2016-08-09 09:22:45

标签: android android-asynctask

我有一个记录音频的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_DOWNrecordSlideBar.setUpRun(Runnable)设置为{{ 1}}到Runnable

基本上,我创建AsyncTask并在调用MotionEvent.ACTION_UP时执行它,并在调用ACTION_DOWN时取消它...

我对整个音频捕获技术不熟悉,因此您可能会在我的代码中看到一些与此相关的错误。请记住,现在的问题是AsyncTask;)

编辑:取消任务后,这是调试器面板的打印屏幕。请注意,AsyncTask状态为 WAIT ,在“变量”标签中,ACTION_UPmCancelledtruemStatus

Screen-shot: asynctask status=wait,cancelled=true,status=running

2 个答案:

答案 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。然后你的循环将需要处理部分读取(以及实际上对数据执行某些操作 - 现在它只是将其读入方法本地数组!)