本期主要內(nèi)容
- 1: 什么是AsyncTask展氓。
- 2: AsyncTask的使用方法申钩。
- 3: AsyncTask的內(nèi)部原理颂碧。
- 4: AsyncTask的注意事項(xiàng)。
- 1: 什么是AsyncTask沫换?
AsyncTask是一個(gè)抽象類(lèi)臭蚁,本質(zhì)上就是封裝了一個(gè)線程池和handler的異步框架,它是由Android封裝的一個(gè)輕量級(jí)異步類(lèi)(輕量體現(xiàn)在使用方便、代碼簡(jiǎn)潔)垮兑,它可以在線程池中執(zhí)行后臺(tái)任務(wù)冷尉,然后把執(zhí)行的進(jìn)度和最終結(jié)果傳遞給主線程并在主線程中更新UI。
AsyncTask的內(nèi)部封裝了兩個(gè)線程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一個(gè)Handler(InternalHandler)系枪。
其中SerialExecutor線程池用于任務(wù)的排隊(duì)雀哨,讓需要執(zhí)行的多個(gè)耗時(shí)任務(wù),按順序排列私爷,THREAD_POOL_EXECUTOR線程池才真正地執(zhí)行任務(wù)雾棺,InternalHandler用于從工作線程切換到主線程。
2: AsyncTask的使用方法
AsyncTask是一個(gè)抽象泛型類(lèi)衬浑。
其中捌浩,三個(gè)泛型類(lèi)型參數(shù)的含義如下:
Params:開(kāi)始異步任務(wù)執(zhí)行時(shí)傳入的參數(shù)類(lèi)型;
Progress:異步任務(wù)執(zhí)行過(guò)程中工秩,返回下載進(jìn)度值的類(lèi)型尸饺;
Result:異步任務(wù)執(zhí)行完成后,返回的結(jié)果類(lèi)型拓诸;
如果AsyncTask確定不需要傳遞具體參數(shù)侵佃,那么這三個(gè)泛型參數(shù)可以用Void來(lái)代替麻昼。
有了這三個(gè)參數(shù)類(lèi)型之后奠支,也就控制了這個(gè)AsyncTask子類(lèi)各個(gè)階段的返回類(lèi)型,如果有不同業(yè)務(wù)抚芦,我們就需要再另寫(xiě)一個(gè)AsyncTask的子類(lèi)進(jìn)行處理倍谜。
2.AsyncTask常用方法總結(jié)
-
onPreExecute
- 這個(gè)方法會(huì)在后臺(tái)任務(wù)開(kāi)始執(zhí)行之間調(diào)用,在主線程執(zhí)行叉抡。用于進(jìn)行一些界面上的初始化操作尔崔,比如顯示一個(gè)進(jìn)度條對(duì)話(huà)框等。
- doInBackground(Params...)
這個(gè)方法中的所有代碼都會(huì)在子線程中運(yùn)行褥民,我們應(yīng)該在這里去處理所有的耗時(shí)任務(wù)季春。
任務(wù)一旦完成就可以通過(guò)return語(yǔ)句來(lái)將任務(wù)的執(zhí)行結(jié)果進(jìn)行返回,如果AsyncTask的第三個(gè)泛型參數(shù)指定的是Void消返,就可以不返回任務(wù)執(zhí)行結(jié)果载弄。注意,在這個(gè)方法中是不可以進(jìn)行UI操作的撵颊,如果需要更新UI元素宇攻,比如說(shuō)反饋當(dāng)前任務(wù)的執(zhí)行進(jìn)度,可以調(diào)用publishProgress(Progress...)方法來(lái)完成倡勇。
-
onProgressUpdate(Progress...)
-
當(dāng)在后臺(tái)任務(wù)中調(diào)用了publishProgress(Progress...)方法后逞刷,這個(gè)方法就很快會(huì)被調(diào)用,方法中攜帶的參數(shù)就是在后臺(tái)任務(wù)中傳遞過(guò)來(lái)的。在這個(gè)方法中可以對(duì)UI進(jìn)行操作夸浅,在主線程中進(jìn)行仑最,利用參數(shù)中的數(shù)值就可以對(duì)界面元素進(jìn)行相應(yīng)的更新。
onProgressUpdate.png
-
-
onPostExecute(Result)
- 當(dāng)doInBackground(Params...)執(zhí)行完畢并通過(guò)return語(yǔ)句進(jìn)行返回時(shí)帆喇,這個(gè)方法就很快會(huì)被調(diào)用词身。返回的數(shù)據(jù)會(huì)作為參數(shù)傳遞到此方法中,可以利用返回的數(shù)據(jù)來(lái)進(jìn)行一些UI操作番枚,在主線程中進(jìn)行法严,比如說(shuō)提醒任務(wù)執(zhí)行的結(jié)果,以及關(guān)閉掉進(jìn)度條對(duì)話(huà)框等葫笼。
上面幾個(gè)方法的調(diào)用順序:
- onPreExecute() --> doInBackground() --> publishProgress() --> onProgressUpdate() --> onPostExecute()
如果不需要執(zhí)行更新進(jìn)度則為
onPreExecute() --> doInBackground() --> onPostExecute(),
除了上面四個(gè)方法深啤,AsyncTask還提供了onCancelled()方法,它同樣在主線程中執(zhí)行路星,當(dāng)異步任務(wù)取消時(shí)溯街,onCancelled()會(huì)被調(diào)用,這個(gè)時(shí)候onPostExecute()則不會(huì)被調(diào)用洋丐,但是要注意的是呈昔,AsyncTask中的cancel()方法并不是真正去取消任務(wù),只是設(shè)置這個(gè)任務(wù)為取消狀態(tài)友绝,我們需要在doInBackground()判斷終止任務(wù)堤尾。就好比想要終止一個(gè)線程,調(diào)用interrupt()方法迁客,只是進(jìn)行標(biāo)記為中斷郭宝,需要在線程內(nèi)部進(jìn)行標(biāo)記判斷然后中斷線程。
3: AsyncTask的內(nèi)部原理
1掷漱、AsyncTask的本質(zhì)是一個(gè)靜態(tài)的線程池粘室,AsyncTask派生出的子類(lèi)可以實(shí)現(xiàn)不同的異步任務(wù),這些任務(wù)都是提交到靜態(tài)的線程池中之行卜范。
2衔统、線程池中的工作線程之行doInBackground(mParams)方法執(zhí)行異步任務(wù)。
3海雪、當(dāng)任務(wù)狀態(tài)改變之后锦爵,工作線程會(huì)向UI線程發(fā)送消息,AsyncTask內(nèi)部的InternalHandler響應(yīng)這些消息喳魏,并調(diào)用相關(guān)的回調(diào)函數(shù)棉浸。
4: AsyncTask的注意事項(xiàng)
- 內(nèi)存泄漏。非靜態(tài)內(nèi)部類(lèi)持有外部類(lèi)的匿名引用刺彩,導(dǎo)致外部類(lèi)無(wú)法被內(nèi)存回收迷郑≈α担可設(shè)為靜態(tài)的。如果AsyncTask被聲明為Activity的非靜態(tài)的內(nèi)部類(lèi)嗡害,那么AsyncTask會(huì)保留一個(gè)對(duì)創(chuàng)建了AsyncTask的Activity的引用焚碌。如果Activity已經(jīng)被銷(xiāo)毀,AsyncTask的后臺(tái)線程還在執(zhí)行霸妹,它將繼續(xù)在內(nèi)存里保留這個(gè)引用十电,導(dǎo)致Activity無(wú)法被回收,引起內(nèi)存泄露叹螟。
生命周期鹃骂。AsyncTask不與任何組件綁定生命周期,所以在Activity/或者Fragment中創(chuàng)建執(zhí)行AsyncTask時(shí)罢绽,最好在Activity/Fragment的onDestory()調(diào)用 cancel(boolean)畏线;
結(jié)果丟失。屏幕旋轉(zhuǎn)或Activity在后臺(tái)被系統(tǒng)殺掉等情況會(huì)導(dǎo)致Activity的重新創(chuàng)建良价,之前運(yùn)行的AsyncTask(非靜態(tài)的內(nèi)部類(lèi))會(huì)持有一個(gè)之前Activity的引用寝殴,這個(gè)引用已經(jīng)無(wú)效,這時(shí)調(diào)用onPostExecute()再去更新界面將不再生效明垢。
-
并行or串行蚣常。一般只使用串行,做不了高并發(fā)的操作痊银。
- 1.6 之前 AsyncTask 是串行執(zhí)行任務(wù)的 抵蚊。
- 1.6 至 2.3 線程池異步任務(wù)并行運(yùn)行 。
- 3.0 以后 異步任務(wù)被按順序 執(zhí)行 曼验。
異步任務(wù)的實(shí)例必須在UI線程中創(chuàng)建泌射,即AsyncTask對(duì)象必須在UI線程中創(chuàng)建。
execute(Params... params)方法必須在UI線程中調(diào)用鬓照。
不要手動(dòng)調(diào)用onPreExecute(),doInBackground(Params... params)孤紧,onProgressUpdate(Progress... values)豺裆,onPostExecute(Result result)這幾個(gè)方法。
不能在doInBackground(Params... params)中更改UI組件的信息号显。
一個(gè)任務(wù)實(shí)例只能執(zhí)行一次臭猜,如果執(zhí)行第二次將會(huì)拋出異常。