2016-08-09 35 views
1

Ich habe eine AsyncTask, die Audio aufzeichnet. Das Problem ist, wenn ich cancel(true) aus dem UI-Thread aufrufen, isCancelled() kehrt true (wie es angenommen hat, zu), aber die doInBackground Funktion läuft weiter, und wenn ich getStatus() auf dem AsyncTask laufen kehrt sie RUNNING und keiner der onCancelled Methoden aufgerufen werden nore tut onPostExecute ...AsyncTask isCancelled() gibt true zurück aber doInBackground endet nicht

Da alle doInBackground Code in while(!isCancelled()) platziert ist, sollte das Verfahren beendet, sobald die Aufgabe ...

abgebrochen

die while (! isCancelled()) Schleife endet, sobald ich AsyncTask.cancel nennen(). Ich denke, das Problem ist, dass return null nicht genannt zu werden, und deshalb doInBackground nicht zu Ende ... ich aber falsch sein kann ...

Code:

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

} 

Hier ist die Teil des Codes in meiner MainActivity Klasse, wo ich anrufen und brechen Sie die 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 ist eine benutzerdefinierte Ansicht, die ich schrieb, dass hat eine o nTouchListener in es recordSlideBar.setDownRun(Runnable) setzt Runnable auf MotionEvent.ACTION_DOWN und recordSlideBar.setUpRun(Runnable) setzt Runnable auf MotionEvent.ACTION_UP.

Grundsätzlich erstelle ich die AsyncTask und führen Sie es aus, wenn ACTION_DOWN genannt wird und es aufheben, wenn ACTION_UP genannt wird ...

Ich bin neu in der gesamten Audio-Capturing-Techniken, so dass Sie einige Fehler in meinem Code sehen könnte in Bezug auf das. Bitte beachten Sie, dass das Problem im Moment die AsyncTask ist;)

EDIT: Hier ist ein Druck-Bildschirm des Debugger-Panel, nachdem ich die Aufgabe abbrechen. feststellen, dass die AsyncTask Status WAIT und in der Registerkarte Variablen ist, mCancelled ist true und mStatusRunning

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

+0

Könnten Sie den Code hinzufügen, wo Sie diese Aufgabe starten und abbrechen ? –

+0

Alles für dich :) –

Antwort

0

Die read Funktion in

int numberOfShort = record.read(audioBuffer, 0, audioBuffer.length); blockiert werden könnte

so ist while(!isCancelled()) darf nie angerufen werden.

Sie Log.d() im while setzen kann zu überprüfen, ob der Code gesperrt ist, wie

while(!isCancelled()) { Log.d("RECTASK","start read"); int numberOfShort = record.read(audioBuffer, 0, audioBuffer.length); numSample +=numberOfShort; Log.d("RECTASK","end read"); }

+0

Ich hatte schon eine Log.d innerhalb der while-Schleife und es funktionierte gut (das Protokoll erschien wieder und wieder, bis isCancelled() wahr geworden, und die Schleife beendet). gelöscht ich das Protokoll, weil es meinen logcat Absturz gemacht ... –

+0

@AlonLevy 'Log.d ("RECTASK", "nach, während \ nisCancelled =" + isCancelled());' Ist das genannt nach stornieren? – Swordsman

+0

Ja. Ich habe die Frage bearbeitet und erklärt, dass die while (isCancelled()) Schleife endet, wie sie sollte –

0

Es klemmt, weil die AudioRecord.read() Verfahren verwendet wird, ist ein blockierender Aufruf der Blöcke in der nativen Ebene statt die Java-Ebene. Der "Interrupt", der als Teil der AsyncTask.cancel() gesendet wird, hat also keine Wirkung.Verwenden Sie anstelle dieser Version von read() die Version, die den readMode-Parameter verwendet, und legen Sie sie auf READ_NON_BLOCKING fest. Ihre Schleife muß dann behandeln Teil liest (wie auch tatsächlich etwas mit den Daten zu tun - jetzt heißt es nur in ein Verfahren lokales Array!)

+0

Habe deine Lösung ausprobiert. immer noch das gleiche Problem. isCancelled() wird wahr und doInBackground läuft weiter. –

+0

Wenn es nicht blockierend ist, sollte das nicht passieren. Schauen Sie sich die Thread-Stacks an und sehen Sie, wo sich der asynchrone Task-Thread innerhalb der Methode 'doInBackground()' befindet. –

+0

Ich sehe jetzt, dass die AsyncTask Status wartet aber ich verstehe nicht, warum ... Wenn Sie auf den Bildschirm-shot ein Blick etwas dagegen, würde ich hinzugefügt und geben Sie Ihre Meinung, die groß sein würde! –