Sau khi gọi AsyncTask.cancel(true)
từ trong vòng doInBackground()
, thay vì gọi onCancelled()
, gọi Android onPostExecute()
. Nhưng as per the documentation:AysncTask tự hủy cuộc gọi vẫn gọi onPostExecute()
gọi method này sẽ dẫn đến
onCancelled(Object)
được gọi trên thread UI saudoInBackground(Object[])
lợi nhuận. Gọi phương thức này đảm bảo rằngonPostExecute(Object)
không bao giờ được gọi.
Đây có phải là lỗi trong Android không?
Nhiều quan sát:
- Calling
cancel(false)
từ một trong hai chủ đề hoạt động như quy định trong tài liệu . - Gọi
cancel(true)
từ tác vụ giao diện người dùng không không gọionPostExecute()
, cũng không némInterruptedException
được nhìn thấy trong dấu vết logcat bên dưới. - Gọi
cancel(false/true)
từ bất kỳ chuỗi nào đôi khi gọionCancelled()
ngay cả trước khi trả lạidoInBackground()
. Đây rõ ràng là vi phạm các tài liệu, which states:
gọi method này sẽ dẫn đến onCancelled (Object) được gọi trên thread UI sau
doInBackground(Object[])
lợi nhuận.
Code: (Thử nghiệm trên thiết bị Android 2.2)
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 ra
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()
Tại sao bạn muốn hủy 'AsyncTask' khỏi' doInBackground'? Điều đó không có ý nghĩa. Phương thức 'cancel (...)' được cố ý có nghĩa là cho phép mã bên ngoài luồng công nhân (nói cách khác trên luồng giao diện người dùng) để tạm dừng thực thi. Nếu mã trong 'doInBackground' cần phải chấm dứt chính nó vì bất kỳ lý do nào thì nó chỉ đơn giản là' return'. Nếu bạn không muốn 'onPostExecute (...)' thực hiện một số hành động như là kết quả của việc hủy giả, sau đó trả về 'false' nếu không trả lại' true' – Squonk
@MisterSquonk, "Phương thức hủy (...) là cố tình có nghĩa là để cho phép mã bên ngoài chuỗi công nhân ngừng hoạt động. " Tài liệu không cho biết nó chỉ được gọi từ chuỗi giao diện người dùng. Tại sao không sử dụng lại mã hiện tại của 'onCancelled()' thay vì sử dụng các cách giải quyết khó coi? –
Đồng ý, tài liệu không nói rằng nó chỉ nên được gọi từ chuỗi giao diện người dùng nhưng điều đó có vẻ hợp lý nhất. Lý do tôi nói đó là tài liệu nói rằng 'doInBackground' nên định kỳ kiểm tra' isCancelled() 'để xem liệu nó có cần tạm dừng thực thi của chính nó (do kết quả của một cuộc gọi đến' hủy') hay không. Nếu có 'doInBackground' gọi là' cancel' là bình thường thì điều gì sẽ là điểm của 'isCancelled()'? – Squonk