2012-04-15 37 views
7

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 sau doInBackground(Object[]) lợi nhuận. Gọi phương thức này đảm bảo rằng onPostExecute(Object) không bao giờ được gọi.

Đây có phải là lỗi trong Android không?

Nhiều quan sát:

  1. Calling cancel(false) từ một trong hai chủ đề hoạt động như quy định trong tài liệu .
  2. Gọi cancel(true) từ tác vụ giao diện người dùng không không gọi onPostExecute(), cũng không ném InterruptedException được nhìn thấy trong dấu vết logcat bên dưới.
  3. Gọi cancel(false/true) từ bất kỳ chuỗi nào đôi khi gọi onCancelled() ngay cả trước khi trả lại doInBackground(). Đâ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() 
+1

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

+0

@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? –

+1

Đồ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

Trả lời

3
  1. Có một ngoại lệ bởi vì bạn gọi hủy (true) mà sẽ gửi một ngắt để thread chạy doInBackground() - Tuy nhiên, trong trường hợp này, bạn đang gọi hủy (true) từ bên trong doInBackground(), do đó khiến cho chuỗi đó ngay lập tức gửi một ngắt tới chính nó.

  2. Mã của bạn đang chạy trên Android 2 nhưng bạn đang trích dẫn các tài liệu dành cho Android 4. Vấn đề là các hành vi trên hủy bỏ() thay đổi giữa Android 2 và Android 4.

    Android 2.3.7 onPostExecute:

    Chạy trên chuỗi giao diện người dùng sau khi làmInBackground. Kết quả được chỉ định là giá trị được trả về bởi doInBackground hoặc null nếu tác vụ đã bị hủy hoặc một ngoại lệ đã xảy ra.

    Android 4.0.1 onPostExecute:

    Chạy trên thread UI sau doInBackground. Kết quả được chỉ định là giá trị được trả về bởi doInBackground. Phương thức này sẽ không được gọi nếu tác vụ đã bị hủy.

1

Bạn nên trả về null và đối xử với sự trở lại trong onPostExecute.

Các vấn đề liên quan