title: AsyncTask isCancelled() returns true but doInBackground doesn't end
body: <p>I have an AsyncTask which record audio. The problem is once I call <code>cancel(true)</code> from the UI thread, <code>isCancelled()</code> returns <code>true</code> (like it's supposed to) but the <code>doInBackground</code> function keeps running and if I run <code>getStatus()</code> on the AsyncTask it returns <strong>RUNNING</strong> and neither of the <code>onCancelled</code> methods are called nore does <code>onPostExecute</code>...</p>
  
  <p>Since all the <code>doInBackground</code> code is placed inside <code>while(!isCancelled())</code>, the method should end once the task is cancelled...</p>
  
  <p>The while(!isCancelled()) loop ends once I call AsyncTask.cancel(). I think the problem is that <code>return null</code> isn't being called and that's why <code>doInBackground</code> doesn't end... I may be wrong though...</p>
  
  <p><strong><em>code:</em></strong></p>
  
  <pre><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&lt;Void,Void,Void&gt; {
  
      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;
      }
  
  }
  </code></pre>
  
  <p>Here's the part of the code in my MainActivity class where I call and cancel the AsyncTask</p>
  
  <pre><code>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);
  
              }
          });
  </code></pre>
  
  <p><code>recordSlideBar</code> is a custom view I wrote that has an onTouchListener in it while <code>recordSlideBar.setDownRun(Runnable)</code> sets a <code>Runnable</code> to the <code>MotionEvent.ACTION_DOWN</code> and <code>recordSlideBar.setUpRun(Runnable)</code> sets a <code>Runnable</code> to the <code>MotionEvent.ACTION_UP</code>.</p>
  
  <p>Basically, I create the AsyncTask and execute it when <code>ACTION_DOWN</code> is called and cancel it when <code>ACTION_UP</code> is called...</p>
  
  <p>I'm new to the whole audio capturing techniques so you might see some errors in my code regarding that. Please remember that the issue right now is the AsyncTask ;)</p>
  
  <p><strong>EDIT:</strong> Here's a print-screen of the debugger panel after I cancel the task. notice that the AsyncTask status is <strong>WAIT</strong>, and in the Variables tab, <code>mCancelled</code> is <code>true</code> and <code>mStatus</code> is <code>Running</code></p>
  
  <p><a href="http://i.stack.imgur.com/oEjvK.jpg" rel="nofollow">Screen-shot: asynctask status=wait,cancelled=true,status=running</a></p>