天天看點

AsyncTask的一些小細節

學習Android的人對AsyncTask應該都不陌生,這個類是基于消息機制封裝的一個類,目的是友善開發者使用。對AsyncTask的基本使用方法就不贅述了,郭霖和鴻洋的部落格中都寫得很清楚了,感謝二位大神。這裡記錄一些使用AsyncTask時的小細節。

關于AsyncTask隻能被執行一次

準确來講,是一個AsyncTask對象隻能被執行一次,即同一個AsyncTask對象,不能多次調用其execute()方法。

為什麼呢?原因大概是同一個任務,執行的肯定是相同的邏輯,可能涉及到對同一塊記憶體區域的讀寫,如果開啟一個以上的線程進行相同的任務,由于線程執行時間的不确定性,無法保證資料的原始性,會造成混亂(可能内部沒有鎖吧)。

那如何防止開發者多次調用execute()方法呢?也很簡單,在AsyncTask對象初始化的時候在其中設定一個final變量的引用,執行execute()之前先檢查該變量,并且在開始執行後對該變量進行指派。這樣第二次執行execute()方法的時候會檢測到不同的該變量,那麼這時候直接報錯就好了。

參考文獻:http://blog.csdn.net/lintcgirl/article/details/48440543

關于AsyncTask内部線程的排程

在API10以前,AsyncTask同時能運作5個線程,其餘線程必須等待。

在API10之後,使用execute()方法開啟的AsyncTask,使用同一個線程池,且所有的任務串行執行,也就是說同時隻有一個任務在執行,當該任務執行完畢後,後面的任務才能執行。這不是開倒車嗎?之前還能同時執行5個,現在隻能同時執行一個?其實并不是,Google同時提供了executeOnExecutor()方法供開發者使用非預設的線程池。顧名思義,要在該方法中傳入一個Executor對象才行。

關于Executor的說明請看這篇文章:

Java并發程式設計

同時Google還提供了兩個預定義的線程池(還有比這更貼心的嗎?):

1. executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR) —和API10之前一樣,可以同時執行5個任務。

2. executeOnExecutor(AsyncTask.SERIAL_EXECUTOR) —和execute()一樣,隻能同時執行一個。

如果想自定義線程池,可以這樣寫:

Executor exec = new ThreadPoolExecutor(, , ,  
    TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());  
           

關于線程池的初始化可以參考上面的文章或下面的參考文章:

參考文獻:

http://blog.csdn.net/hitlion2008/article/details/7983449

PS:我一直在思考“封裝”這個概念,對于老手來說,封裝确實友善了使用,但是對于新手來說,封裝也隐藏了内部的實作細節,使得新手隻知其然而不知其是以然,不出問題還好,一出問題就束手無策了。是以我覺得,如果時間和精力允許的話,對于封裝過的子產品還是盡量了解下其内部基本實作會比較好。