简体   繁体   中英

Timing of execution of AsyncTask onCancelled() and AsyncTask.doInBackground()

According to the Android Reference for the AsyncTask.cancel method , the timing between onCancelled() and doInBackground() is explicitly defined:

Calling this method will result in onCancelled(Object) being invoked on the UI thread after doInBackground(Object[]) returns. Calling this method guarantees that onPostExecute(Object) is never invoked

However, looking at my logcat I can see that the onCancelled() method is executed before the doInBackground() method returns.

07-10 12:38:57.000: VERBOSE/AsyncTask(7473): doInBackground entered
07-10 12:38:57.000: VERBOSE/AsyncTask(7473): AsyncTask attempting to take the lock
07-10 12:38:57.000: VERBOSE/AsyncTask(7473): AsyncTask got the lock
07-10 12:38:57.420: VERBOSE/AsyncTask(7473): Start Item[0].state = 0
07-10 12:38:57.933: VERBOSE/AsyncTask(7473): onProgressUpdate entered
07-10 12:38:57.940: VERBOSE/AsyncTask(7473): onProgressUpdate exited
07-10 12:38:58.320: VERBOSE/(7473): onCancelListener cancelling AsyncTask
07-10 12:38:58.400: VERBOSE/AsyncTask(7473): onCancelled entered
07-10 12:38:58.400: VERBOSE/AsyncTask(7473): onCancelled exited
07-10 12:38:58.560: VERBOSE/AsyncTask(7473): Started checking file URL
07-10 12:38:58.601: VERBOSE/FileHost(7473): checkFile entered
07-10 12:38:58.641: VERBOSE/FileHost(7473): checkFile checking URI
07-10 12:38:58.691: DEBUG/dalvikvm(7473): threadid=19 wakeup: interrupted
07-10 12:38:58.710: VERBOSE/AsyncTask(7473): AsyncTask released the lock
07-10 12:38:58.710: VERBOSE/AsyncTask(7473): doInBackground exited

Using the debugger and setting breakpoints at the onCancelled() method and the end of the doInBackground() method, I can also see that onCancelled() is called before the end of the doInBackground().

Is there some way that I have mis-coded something in my AsyncTask to bring about this difference in behaviour between the Android Reference and my application behaviour?

Edited to add some code for Gallal:

@Gallal, the Activity contains this piece of code.

private class OnCancelListener implements AddUrlDialog.CancelListener {
  @Override
  public void cancel() {
    if (addUrlInProgress == true) {
      addUrlInProgress = false;
      Log.v(TAG, "onCancelListener cancelling AsyncTask");
      addUrlControl.stopUpdates(true);
      AddUrlDialog.dismiss();
    }
  } 
}

The AsyncTask.cancel is called in the addUrlControl.stopUpdates() method.

public void stopUpdates(boolean cleanupLists) {
  if (asyncTaskExited != true) {
      cancelRequest = true; 
        addUrlAsyncTask.cancel(true);
        //TEST httpRequest.abort(); // Also sends an abort to the HTTP request
  }
}

The AsyncTask doInBackground method looks likes this.

@Override
protected Void doInBackground(Void... v) {
  Log.v(TAG, "doInBackground entered");

    netConn = addUrlControl.myApp.getNetConn();
    client = netConn.getHttpClient();

    try {
      doInBackgroundBody();
  } catch (Throwable t) {
      Log.e(TAG, "doInBackgroundBody threw an exception: ", t);
  } finally {
      addUrlControl.myApp.releaseNetConn();
  }

    Log.v(TAG, "doInBackground exited");        
    return null;
}

I can confirm (as some of you already stated) that there is a bug in the Android source for 2.x versions that makes onCancelled() be called just after cancel() and before doInBackground() finishes.

So, if you were doing the clean up in onCancelled() you will actually do this at the same time as the AsyncTask is running and this will crash your app. This makes us change the design...

Hope it helps!

What does

addUrlAsyncTask.cancel(true);

return?

If the Task cannot be interrupted it will run until it is finished.

Do you have a loop inside doInBackgroundBody()? Ie the following implementation of doInBackground() would catch the InterruptedException that is thrown when calling myTask.cancel(true) and thus the loop will go on until the loop condition does evaluate to false.

        int count = 0;
        while(count++ < 10){
            try {
                Log.d("MyAsyncTask", "WORKING doInBackground() is cancelled: " + this.isCancelled());
                Thread.sleep(1000);

            } catch (Exception e) {
                e.printStackTrace();
                //break or return missing here to end the loop
            }
        }

This seems to be related to a bug that I haven't been able to find a whole lot of information about. Except that I'm having the same problem. According to this discussion: AsyncTask's cancel method - possible bug it's a race in the cancel() code that should be fixed in post froyo builds.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM