2012-04-15 8 views
7

Nach AsyncTask.cancel(true) aus doInBackground() Aufruf, anstatt onCancelled() aufzurufen, ruft Android onPostExecute(). Aber as per the documentation:AysncTask Cancelling selbst noch ruft OnPostExecute()

Aufruf dieser Methode wird in onCancelled(Object) dazu führen, dass nach doInBackground(Object[]) kehrt auf dem UI-Thread aufgerufen. Durch den Aufruf dieser Methode wird garantiert, dass onPostExecute(Object) nie aufgerufen wird.

Ist es ein Fehler in Android?

Weitere Beobachtungen:

  1. Aufruf cancel(false) von entweder Thread in der Dokumentation wie angegeben funktioniert.
  2. Aufruf cancel(true) aus der UI Aufgabe hat nicht Anruf onPostExecute(), noch werfen sie die InterruptedException im logcat gesehen unter nachzeichnet.
  3. Aufruf von cancel(false/true) von einem Thread ruft manchmal onCancelled() noch bevor doInBackground() zurückgibt. Dies ist eindeutig eine Verletzung der Dokumentation, which states:

Aufruf dieser Methode in onCancelled (Object) führt nachdoInBackground(Object[]) kehrt auf dem UI-Thread aufgerufen wird.

Code: (Getestet auf Android 2.2-Gerät)

protected Void doInBackground(Void... params) { 
    Log.d(TAG, "started doInBackground()"); 
    while (!isCancelled()) { 
     boolean ret = cancel(true); 
     Log.d(TAG, "cancel() returned: " + ret); 
    } 
    Log.d(TAG, "returning from doInBackground()"); 
    return null; 
} 

Logcat Ausgang

04-15 21:38:55.519: D/MyTask(27597): started doInBackground() 
04-15 21:38:55.589: W/AsyncTask(27597): java.lang.InterruptedException 
04-15 21:38:55.589: W/AsyncTask(27597):  at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1254) 
04-15 21:38:55.589: W/AsyncTask(27597):  at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:219) 
04-15 21:38:55.589: W/AsyncTask(27597):  at java.util.concurrent.FutureTask.get(FutureTask.java:82) 
04-15 21:38:55.589: W/AsyncTask(27597):  at android.os.AsyncTask$3.done(AsyncTask.java:196) 
04-15 21:38:55.589: W/AsyncTask(27597):  at java.util.concurrent.FutureTask$Sync.innerCancel(FutureTask.java:293) 
04-15 21:38:55.589: W/AsyncTask(27597):  at java.util.concurrent.FutureTask.cancel(FutureTask.java:75) 
04-15 21:38:55.589: W/AsyncTask(27597):  at android.os.AsyncTask.cancel(AsyncTask.java:325) 
04-15 21:38:55.589: W/AsyncTask(27597):  at com.example.test.TestActivity$MyTask.doInBackground(TestActivity.java:31) 
04-15 21:38:55.589: W/AsyncTask(27597):  at com.example.test.TestActivity$MyTask.doInBackground(TestActivity.java:1) 
04-15 21:38:55.589: W/AsyncTask(27597):  at android.os.AsyncTask$2.call(AsyncTask.java:185) 
04-15 21:38:55.589: W/AsyncTask(27597):  at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) 
04-15 21:38:55.589: W/AsyncTask(27597):  at java.util.concurrent.FutureTask.run(FutureTask.java:137) 
04-15 21:38:55.589: W/AsyncTask(27597):  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068) 
04-15 21:38:55.589: W/AsyncTask(27597):  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561) 
04-15 21:38:55.589: W/AsyncTask(27597):  at java.lang.Thread.run(Thread.java:1096) 
04-15 21:38:55.589: D/MyTask(27597): cancel() returned: true 
04-15 21:38:55.589: D/MyTask(27597): returning from doInBackground() 
04-15 21:38:55.659: D/MyTask(27597): onPostExecute() 
+1

Warum wollen Sie von einem 'AsyncTask' abzubrechen innerhalb' doInBackground'? Das ergibt keinen Sinn. Die 'cancel (...)' -Methode ist bewusst dazu gedacht, Code außerhalb des Worker-Threads (mit anderen Worten auf dem UI-Thread) zu erlauben, die Ausführung anzuhalten. Wenn sich der Code in 'doInBackground' aus irgendeinem Grund selbst beenden muss, sollte er einfach 'zurückgeben'. Wenn Sie nicht möchten, dass 'onPostExecute (...)' bestimmte Aktionen als Ergebnis eines Pseudo-Cancel ausführt, dann geben Sie 'false' zurück, andernfalls geben Sie' true' zurück. – Squonk

+0

@MisterSquonk, "Die cancel (...) Methode ist bewusst dazu gedacht, Code außerhalb des Worker-Threads zuzulassen, um die Ausführung anzuhalten. " Die Dokumentation besagt nicht, dass sie nur vom UInthread aufgerufen werden soll. Warum nicht den vorhandenen Code von 'onCancelled() 'anstelle von unschönen Workarounds verwenden? –

+1

Vereinbart, die Dokumentation sagt nicht, dass es nur aus dem UI-Thread aufgerufen werden sollte, aber das scheint am logischsten. Der Grund, warum ich das sage, ist, dass die Dokumentation sagt, dass "doInBackground" regelmäßig "isCancelled()" überprüfen sollte, um zu sehen, ob es seine eigene Ausführung anhalten muss (als Folge eines Aufrufs von 'cancel'). Wenn "doInBackground" 'cancel' aufrufen ist normal, was wäre dann der Punkt von' isCancelled() '? – Squonk

Antwort

3
  1. Es gibt eine Ausnahme, weil Sie stornieren nennen (true), die eine Unterbrechung an den Faden doInBackground() sendet - in diesem Fall jedoch, rufen Sie (true) Abbrechen von innen doInBackground(), so dass Veranlassung, dass der Thread sofort eine Unterbrechung an sich selbst sendet.

  2. Der Code wird auf Android läuft 2, aber Sie zitieren die Dokumentation für Android 4. Das Problem ist, dass das Verhalten auf cancel() zwischen Android 2 und Android

    Android 2.3.7 onPostExecute geändert 4.:

    Wird auf dem UI-Thread nach doInBackground ausgeführt. Das angegebene Ergebnis ist der von doInBackground zurückgegebene Wert oder null, wenn die Aufgabe abgebrochen wurde oder eine Ausnahme aufgetreten ist.

    Android 4.0.1 onPostExecute:

    Läuft auf dem UI-Thread nach doInBackground. Das angegebene Ergebnis ist der von doInBackground zurückgegebene Wert. Diese Methode wird nicht aufgerufen, wenn die Aufgabe abgebrochen wurde.

1

Sie sollten null zurück, und die Rückkehr in die OnPostExecute behandeln.

Verwandte Themen