1. 程式人生 > >AsyncTask中cancel方法的誤讀

AsyncTask中cancel方法的誤讀

你是否遇到過使用AsyncTask做下載邏輯時,在下載進行到一半點選返回鍵,然後再次回到下載介面時,執行緒並未立即執行,而是過一段時間之後才開始。為了究其原因,我寫了個Demo進行了下驗證。

Demo很簡單,主要就是展示一個進度條,在doInBackground中用一個for迴圈來定時傳送publishProgress(i),在onProgressUpdate中接受傳遞過來的i,然後讓進度條進行顯示。

執行後你會發現進度條會按照既定設定進行百分比顯示,但是後來你就發現,一旦你在顯示過程中點選返回鍵退出程式,然後再次進入程式,你會發現進度條並未立即顯示,而是等了一段時間後才開始執行。原因就是AsyncTask維護了一個執行緒池,你點選返回的時候並未結束當前執行緒的執行,所以你再次開啟的時候,系統會先將上一次的執行緒結束之後,再開始新的執行緒。

解決方案,我們需要在退出時候給執行緒傳送一個執行緒終止的操作,讓當前執行緒停下來,這樣才能在下次開始時候立即執行新執行緒。這就有用到了生命週期的相關概念了,具體可以參考我的另一篇文章:專案中回退Fragment導致介面重新整理的猜想。我們在onPause中進行停止執行緒操作,程式碼如下:

@Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
        if(myTask != null && myTask.getStatus() == AsyncTask.Status.RUNNING){
            myTask.cancel(true
); } }

之後再次執行程式,咦,發現問題依舊,原因是cancel()方法並非是直接停止當前執行緒,而是傳送一個停止執行緒的狀態位,也就是說將執行緒池中的某個控制狀態的標誌位變為CANCEL狀態。於是我們還需要繼續進行編碼,在傳送進度的時候判斷下執行緒是否取消狀態,即isCancelled(),如果是,break或者return出去。

OK了,再次執行程式,看下是否可以立即執行了?

小結下:寫本篇文章的目的就是讓大家知道並非cancel方法就能立即終止執行緒,並非所有的方法是見名知意,這個以後得多加註意。另外就是我發現好多涉及到執行緒的程式碼,只是寫了執行緒執行時候的各種操作,而不去考慮執行緒何時終止,終止後有何操作的邏輯,會無故引發很多的bug。