AsyncTask是什么?(What)
AsyncTask是一種輕量級的異步任務(wù)類,它可以在線程池中執(zhí)行后臺任務(wù),然后把執(zhí)行的進(jìn)度和最終結(jié)果傳遞給主線程并在主線程中更新UI。
AsyncTask是一個(gè)抽象的泛型類,它提供了Params、Progress和Result這三個(gè)泛型參數(shù),其中Params表示參數(shù)的類型,Progress表示后臺任務(wù)的執(zhí)行進(jìn)度和類型,而Result則表示后臺任務(wù)的返回結(jié)果的類型,如果AsyncTask不需要傳遞具體的參數(shù),那么這三個(gè)泛型參數(shù)可以用Void來代替。
AsyncTask原理(How)
AsyncTask的實(shí)現(xiàn)原理 = 線程池 + Handler
其中:線程池用于線程調(diào)度、復(fù)用 & 執(zhí)行任務(wù);Handler 用于異步通信
- AsyncTask中有兩個(gè)線程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一個(gè)Handler(InternalHandler),其中線程池SerialExecutor用于任務(wù)的排隊(duì),而線程池THREAD_POOL_EXECUTOR用于真正地執(zhí)行任務(wù),InternalHandler用于將執(zhí)行環(huán)境從線程池切換到主線程。
- sHandler是一個(gè)靜態(tài)的Handler對象,為了能夠?qū)?zhí)行環(huán)境切換到主線程,這就要求sHandler這個(gè)對象必須在主線程創(chuàng)建。由于靜態(tài)成員會在加載類的時(shí)候進(jìn)行初始化,因此這就變相要求AsyncTask的類必須在主線程中加載,否則同一個(gè)進(jìn)程中的AsyncTask都將無法正常工作。


AsyncTask注意事項(xiàng)
關(guān)于線程池:
AsyncTask對應(yīng)的線程池ThreadPoolExecutor都是進(jìn)程范圍內(nèi)共享的,且都是static的,所以是Asynctask控制著進(jìn)程范圍內(nèi)所有的子類實(shí)例。由于這個(gè)限制的存在,當(dāng)使用默認(rèn)線程池時(shí),如果線程數(shù)超過線程池的最大容量,線程池就會爆掉(3.0后默認(rèn)串行執(zhí)行,不會出現(xiàn)個(gè)問題)。針對這種情況,可以嘗試自定義線程池,配合Asynctask使用。
關(guān)于默認(rèn)線程池:
AsyncTask里面線程池是一個(gè)核心線程數(shù)為CPU + 1,最大線程數(shù)為CPU * 2 + 1,工作隊(duì)列長度為128的線程池,線程等待隊(duì)列的最大等待數(shù)為28,但是可以自定義線程池。線程池是由AsyncTask來處理的,線程池允許tasks并行運(yùn)行,需要注意的是并發(fā)情況下數(shù)據(jù)的一致性問題,新數(shù)據(jù)可能會被老數(shù)據(jù)覆蓋掉。所以希望tasks能夠串行運(yùn)行的話,使用SERIAL_EXECUTOR。
AsyncTask在不同的SDK版本中的區(qū)別:
調(diào)用AsyncTask的execute方法不能立即執(zhí)行程序的原因及改善方案通過查閱官方文檔發(fā)現(xiàn),AsyncTask首次引入時(shí),異步任務(wù)是在一個(gè)獨(dú)立的線程中順序的執(zhí)行,也就是說一次只執(zhí)行一個(gè)任務(wù),不能并行的執(zhí)行,從1.6開始,AsyncTask引入了線程池,支持同時(shí)執(zhí)行5個(gè)異步任務(wù),也就是說只能有5個(gè)線程運(yùn)行,超過的線程只能等待,等待前的線程直到某個(gè)執(zhí)行完了才被調(diào)度和運(yùn)行。換句話說,如果進(jìn)程中的AsyncTask實(shí)例個(gè)數(shù)超過5個(gè),那么假如前5都運(yùn)行很長時(shí)間的話,那么第6個(gè)只能等待機(jī)會了。這是AsyncTask的一個(gè)限制,而且對于2.3以前的版本無法解決。如果你的應(yīng)用需要大量的后臺線程去執(zhí)行任務(wù),那么只能放棄使用AsyncTask,自己創(chuàng)建線程池來管理Thread。不得不說,雖然AsyncTask較Thread使用起來方便,但是它最多只能同時(shí)運(yùn)行5個(gè)線程,這也大大局限了它的作用,你必須要小心設(shè)計(jì)你的應(yīng)用,錯(cuò)開使用AsyncTask時(shí)間,盡力做到分時(shí),或者保證數(shù)量不會大于5個(gè),否就會遇到上面提到的問題。可能是Google意識到了AsynTask的局限性了,從Android 3.0開始對AsyncTask的API做出了一些調(diào)整:每次只啟動一個(gè)線程執(zhí)行一個(gè)任務(wù),完了之后再執(zhí)行第二個(gè)任務(wù),也就是相當(dāng)于只有一個(gè)后臺線程在執(zhí)行所提交的任務(wù)。
一些問題:
1.生命周期
很多開發(fā)者會認(rèn)為一個(gè)在Activity中創(chuàng)建的AsyncTask會隨著Activity的銷毀而銷毀。然而事實(shí)并非如此。AsynTask會一直執(zhí)行,直到doInBackground()方法執(zhí)行完畢,然后,如果cancel(boolean)被調(diào)用,那么onCancelled(Result result)方法會被執(zhí)行;否則,執(zhí)行onPostExecute(Result result)方法。如果我們的Activity銷毀之前,沒有取消AsyncTask,這有可能讓我們的應(yīng)用崩潰(crash)。因?yàn)樗胍幚淼膙iew已經(jīng)不存在了。所以,我們是必須確保在銷毀活動之前取消任務(wù)??傊覀兪褂肁syncTask需要確保AsyncTask正確的取消。
2.內(nèi)存泄漏
如果AsyncTask被聲明為Activity的非靜態(tài)內(nèi)部類,那么AsyncTask會保留一個(gè)對Activity的引用。如果Activity已經(jīng)被銷毀,AsyncTask的后臺線程還在執(zhí)行,它將繼續(xù)在內(nèi)存里保留這個(gè)引用,導(dǎo)致Activity無法被回收,引起內(nèi)存泄漏。
3.結(jié)果丟失
屏幕旋轉(zhuǎn)或Activity在后臺被系統(tǒng)殺掉等情況會導(dǎo)致Activity的重新創(chuàng)建,之前運(yùn)行的AsyncTask會持有一個(gè)之前Activity的引用,這個(gè)引用已經(jīng)無效,這時(shí)調(diào)用onPostExecute()再去更新界面將不再生效。
4.并行還是串行
在Android1.6之前的版本,AsyncTask是串行的,在1.6之后的版本,采用線程池處理并行任務(wù),但是從Android 3.0開始,為了避免AsyncTask所帶來的并發(fā)錯(cuò)誤,又采用一個(gè)線程來串行執(zhí)行任務(wù)。可以使用executeOnExecutor()方法來并行地執(zhí)行任務(wù)。