AsyncTask
常遇到的一個典型的使用場景:用戶切換到某個界面,觸發了界面上的圖片的加載操作,因為圖片的加載相對來說耗時比較長,我們需要在子線程中處理圖片的加載,當圖片在子線程中處理完成之後,再把處理好的圖片返回給主線程,交給UI更新到畫面上。
AsyncTask的出現就是為了快速的實現上面的使用場景,AsyncTask把在主線程裡面的準備工作放到onPreExecute()
方法裡面進行執行,doInBackground()
方法執行在工作線程中,用來處理那些繁重的任務,一旦任務執行完畢,就會調用onPostExecute()
方法返回到主線程。
使用AsyncTask需要注意的問題有哪些呢?請關注以下幾點:
- 首先,默認情況下,所有的AsyncTask任務都是被線性調度執行的,他們處在同一個任務隊列當中,按順序逐個執行。假設你按照順序啟動20個AsyncTask,一旦其中的某個AsyncTask執行時間過長,隊列中的其他剩餘AsyncTask都處於阻塞狀態,必須等到該任務執行完畢之後才能夠有機會執行下一個任務。情況如下圖所示:
為瞭解決上面提到的線性隊列等待的問題,我們可以使用AsyncTask.executeOnExecutor()
強制指定AsyncTask使用Thread Pool Concurrent Schedule Task(Thread並行排程任務)。
- 其次,如何才能夠真正的取消一個AsyncTask的執行呢?我們知道AsyncTaks有提供
cancel()
的方法,但是這個方法實際上做了什麼事情呢?線程本身並不具備中止正在執行的代碼的能力,為了能夠讓一個線程更早的被銷毀,我們需要在doInBackground()
的代碼中不斷的添加程序是否被中止的判斷邏輯,如下圖所示:
一旦任務被成功中止,AsyncTask就不會繼續調用onPostExecute()
,而是通過調用onCancelled()
的回調方法反饋任務執行取消的結果。我們可以根據任務回調到哪個方法(是onPostExecute還是onCancelled)來決定是對UI進行正常的更新還是把對應的任務所佔用的內存進行銷毀等。
- 最後,使用AsyncTask很容易導致內存洩漏,一旦把AsyncTask寫成Activity的內部類的形式就很容易因為AsyncTask生命週期的不確定而導致Activity發生洩漏。
綜上所述,AsyncTask雖然提供了一種簡單便捷的異步機制,但是我們還是很有必要特別關注到他的缺點,避免出現因為使用錯誤而導致的嚴重系統性能問題。