記得2012年的時候,在MTK公司內(nèi)部的一個Work Shop上我分享了對AsyncTask的理解,聽眾都很有興趣地參與討論使用AsyncTask的問題所在。因為UI線程阻塞的問題,每一個Android應用開發(fā)都會遇到要開工作線程中去做耗時間的操作,相對于new Thread再使用Handler更新UI的話,直接使用AsyncTask無疑是最經(jīng)濟方便的選擇。
關(guān)于AsyncTask有很多是非,如最早的128數(shù)量限制,后來MTK的同事還發(fā)現(xiàn)AsyncTask中的Handler Bug:在工作線程中先使用AsyncTask會造成它里面的Handler是指向工作線程的Looper(如果這個工作線程沒有創(chuàng)建Looper,程序會崩潰),而這個Handler是靜態(tài)的,會造成之后無法在onPostExecute方法中更新UI。在Android 4.1版本Google修改了這個BUG,把AsyncTask的初始化放到ActivityThread.main中去創(chuàng)建,以確保它的靜態(tài)Handler指向主線程的Looper。
AsyncTask.init();
面試題:在項目中使用AsyncTask會有什么問題嗎?
那我們考查AsyncTask會問些什么呢?得先問問會不會用吧,看看知不知道有onProgressUpdate方法。
其次問一下是怎么理解AsyncTask的機制,有沒有看過它的源代碼?
這個問題主要看對方是否對Android的東西有好奇心,會主動去看AsyncTask的源碼,或者能大體地講清楚AsyncTask的原理。一般有好奇心的同學都比較善長學習,善長學習的人都能比較快融入團隊。
AnsycTask執(zhí)行任務時,內(nèi)部會創(chuàng)建一個進程作用域的線程池來管理要運行的任務,也就就是說當你調(diào)用了AsyncTask.execute()后,AsyncTask會把任務交給線程池,由線程池來管理創(chuàng)建Thread和運行Therad。最后和UI打交道就交給Handler去處理了。
我們在實際的項目中,還需要關(guān)注一些問題:
線程池可以同時執(zhí)行多少個TASK?
Android 3.0之前(1.6之前的版本不再關(guān)注)規(guī)定線程池的核心線程數(shù)為5個(corePoolSize),線程池總大小為128(maximumPoolSize),還有一個緩沖隊列(sWorkQueue,緩沖隊列可以放10個任務),當我們嘗試去添加第139個任務時,程序就會崩潰。當線程池中的數(shù)量大于corePoolSize,緩沖隊列已滿,并且線程池中的數(shù)量小于maximumPoolSize,將會創(chuàng)建新的線程來處理被添加的任務。如下圖會出現(xiàn)第16個Task比第6-15個Task先執(zhí)行的情況。

多個AsyncTask任務是串行還是并行?
從Android 1.6到2.3(Gingerbread) AsyncTask是并行的,即上面我們提到的有5個核心線程的線程池(ThreadPoolExecutor)負責調(diào)度任務。從Android 3.0開始,Android團隊又把AsyncTask改成了串行,默認的Executor被指定為SERIAL_EXECUTOR。
/**
* An {@link Executor} that executes tasks one at a time in serial
* order. This serialization is global to a particular process.
*/
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
從它的說明也可以看出是串行的。如需要并行,可以通過設置executeOnExecutor(Executor)來實現(xiàn)多個AsyncTask并行。
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
AsyncTask容易引發(fā)的Activity內(nèi)存泄露
如果AsyncTask被聲明為Activity的非靜態(tài)的內(nèi)部類,那么AsyncTask會保留一個對創(chuàng)建了AsyncTask的Activity的引用。如果Activity已經(jīng)被銷毀,AsyncTask的后臺線程還在執(zhí)行,它將繼續(xù)在內(nèi)存里保留這個引用,導致Activity無法被回收,引起內(nèi)存泄露。
當然,最后少不了問一句:“你在項目中,會用什么方案來替換AsyncTask呢?”
小結(jié)
感覺對AsyncTask的使用有點“成也蕭何敗蕭何”的味道,它簡單的解決了UI和后臺線程交互的問題,但如果忽視它的限制(缺陷)和各版本不一致的線程池方式,可能會達不到預想的效果。最后發(fā)現(xiàn)沒有使用過AsyncTask會被鄙視,如果你在實際項目中使用了AsyncTask也會被鄙視。不過,學習它對理解Android的機制和線程池的使用還是很的意義的,所以強烈建議大家讀一下它的源碼。