AsyncTask小酌

前言:最近的目標(biāo)就是跳槽,跳槽完再搭個(gè)站,這樣的話生活就充實(shí)一點(diǎn)點(diǎn)了吧。

今天說的AsyncTask也是項(xiàng)目中常常會用到的,面試中常常會問到的。可是我一般都不用這個(gè)的,但是新項(xiàng)目中也需要網(wǎng)絡(luò)請求框架啊,而且asynctask這種不需要new thread和handler就能實(shí)現(xiàn)異步更新,我是非常贊賞的,因?yàn)楹芏嗑W(wǎng)絡(luò)框架其實(shí)都是基于這樣的消息通知機(jī)制,把網(wǎng)絡(luò)請求封裝在底層,用戶只需要重寫回調(diào)接口的方法即可!

Enum枚舉類

經(jīng)過我長久以來積攢的經(jīng)驗(yàn),當(dāng)分析源碼的時(shí)候,最好先找一下類中的枚舉常量,知道他們大概是代表什么意思,在什么情景下會使用到

指定任務(wù)的當(dāng)前狀態(tài)

在任務(wù)的生命周期,任務(wù)的每一個(gè)的狀態(tài)只會被指定一次,如果任務(wù)還沒有被執(zhí)行,那么狀態(tài)為PENDING,如果任務(wù)正在運(yùn)行,那么指定為RUNNING,如果任務(wù)已經(jīng)執(zhí)行完畢了,那么狀態(tài)指定為FINISHED。一個(gè)整體上的了解,AsyncTask有三個(gè)狀態(tài),分別為運(yùn)行前,中,后。

AsyncTask

AsyncTask能夠在UI線程使用,它不需要操作Thread和Handler就可以實(shí)現(xiàn)進(jìn)行后臺操作和在UI線程顯示結(jié)果。

AsyncTask并不是一個(gè)通用的線程框架,而是作為一個(gè)在Thread和Handler之間的工具類。AsyncTask理論上用來執(zhí)行少量的操作(最多花費(fèi)幾秒)。如果需要保持線程運(yùn)行很長一段時(shí)間,強(qiáng)烈建議你使用java.util.concurrent提供的其他的API,比如Executor,ThreadPoolExecutor和FutureTask(有關(guān)線程池部分的內(nèi)容)。

完成一次異步任務(wù),我們在定義的時(shí)候可以根據(jù)需要定義三種類型的變量ParamsProgressResult,四個(gè)步驟onPreExecutedoInBackgroundonProgressUpdateonPostExecute即可。派生一個(gè)子類,這個(gè)子類必須重寫doInBackground方法,通常還會重寫的第二個(gè)方法是onPostExecute來展示運(yùn)行的結(jié)果。

官方提供的用例

異步任務(wù)中的三種類型的參數(shù)分別如下:

Params:在任務(wù)執(zhí)行之前,發(fā)送給任務(wù)的參數(shù)類型

Progress:后臺線程計(jì)算的時(shí)候,輸出的進(jìn)度單元

Result:后臺線程計(jì)算的結(jié)果的類型

哲學(xué)參數(shù)都是可選的,為了標(biāo)記一個(gè)類型沒有被使用,簡單的使用Void類型即可,要是什么參數(shù)都不需要設(shè)定的話,那么使用<Void,Void,Void>即可。

AsyncTask創(chuàng)建——執(zhí)行的過程:

AsyncTask的創(chuàng)建

AsyncTask是一個(gè)抽象類,所以要實(shí)例化必須要?jiǎng)?chuàng)建一個(gè)繼承自AsyncTask的子類,我們在創(chuàng)建這個(gè)子類的時(shí)候就會指定各種參數(shù)的類型,在AsyncTask的構(gòu)造函數(shù)中,就做了兩樣事情,一個(gè)是創(chuàng)建一個(gè)Callable對象mWorker,一個(gè)是根據(jù)mWorker創(chuàng)建一個(gè)FutureTask,記住,AsyncTask是一次性的買賣

關(guān)于設(shè)置線程優(yōu)先級,setPriority是JDK提供的方法,而Process.setThreadPriority是Android的方法。我們都知道任何線程他們執(zhí)行的都是Runnable方法,不管是繼承Thread,或者是實(shí)現(xiàn)Runnable接口,實(shí)際上都是實(shí)現(xiàn)的run方法,而Callable我們可以理解成的是一個(gè)有返回值的run方法,這個(gè)Callable到最后也會適配成一個(gè)Runnable,適配的工作就是交由FutureTask來完成。

任務(wù)實(shí)體

FutureTask是一個(gè)管理Callable的類,有關(guān)Future相關(guān)的字樣總是離不開Callable的,在AsyncTask的構(gòu)造方法內(nèi),通過mWorker來創(chuàng)建了一個(gè)FutureTask對象

這里先簡單介紹一下FutureTask,F(xiàn)utureTask實(shí)現(xiàn)了RunnableFuture接口,這個(gè)RunnableFuture接口繼承了Runnable和Future接口,F(xiàn)uture接口里面其實(shí)是一些針對Callback的操作,比如cancel,done,get等,用于獲取call的結(jié)果,取消call等。而FutureTask內(nèi)部有一個(gè)Callable<V>的成員變量callable

再看FutureTask的兩個(gè)構(gòu)造函數(shù),可以從這兩個(gè)構(gòu)造函數(shù)中看出,F(xiàn)utureTask的構(gòu)造其實(shí)就是要初始化callable對象,如果傳入的是一個(gè)Runnable對象,就同Executors的callable方法適配成callable對象(Executors其實(shí)是一個(gè)封裝好的工具類)

Callback參數(shù)
Runnable參數(shù)
result對象是返回值,因此task要負(fù)責(zé)對result進(jìn)行計(jì)算

至此我們就獲得一個(gè)FutureTask,它才是異步任務(wù)的大功臣,AsyncTask只是發(fā)言代表而已。AsyncTask還添加了一些類似于get,cancel等方法,其實(shí)是AsyncTask提供給外部,對FutureTask進(jìn)行直接控制的方法。get方法分阻塞和超時(shí)非阻塞兩種,一般使用情況不多。

AsyncTask的運(yùn)行

當(dāng)一個(gè)異步任務(wù)執(zhí)行的時(shí)候,我們會調(diào)用execute這個(gè)方法,并且任務(wù)的執(zhí)行過程會經(jīng)歷四個(gè)步驟:

以下四個(gè)方法都是需要默認(rèn)空實(shí)現(xiàn)需要我們重寫的方法。

1、onPreExecute(戰(zhàn)前動員)

在任務(wù)執(zhí)行之前,在UI線程中調(diào)用,這一步驟通常用來安裝任務(wù),比如顯示一個(gè)進(jìn)度條在用戶界面,很多時(shí)候我們都沒有重寫這個(gè)方法的。

2、doInBackground

onPreExecute執(zhí)行完畢之后就會調(diào)用doInBackground,而doInBackground是mWorker中的call回調(diào)中被調(diào)用,這一步被用來執(zhí)行耗時(shí)的后臺計(jì)算,AsyncTask的Params參數(shù)會傳遞到這一步驟,計(jì)算的結(jié)果必須在這一步被返回,當(dāng)我們調(diào)用execute的時(shí)候,就會調(diào)用起這個(gè)方法,執(zhí)行耗時(shí)操作了。

默認(rèn)的任務(wù)管理器
自定義的任務(wù)池

當(dāng)我們調(diào)用AsyncTask的execute時(shí),就會往任務(wù)池里面添加一個(gè)runnable任務(wù),并且自動執(zhí)行任務(wù)池里的任務(wù),執(zhí)行完一個(gè)的時(shí)候執(zhí)行下一個(gè),正常情況下其實(shí)只會有一個(gè)任務(wù),那就時(shí)構(gòu)造函數(shù)內(nèi)實(shí)現(xiàn)的mFuture對象

execute

3、onProgressUpdate

execute的時(shí)候,可以在doInBackground中主動調(diào)用publishProgress來輸出一個(gè)或者多個(gè)進(jìn)度值(Progresser類型值),這些值都可以在在onProgressUpdate這一步直接在UI線程通過進(jìn)度條等方式顯示出來。即使后臺計(jì)算仍在運(yùn)行,這個(gè)方法可以在UI進(jìn)程中顯示任何形式的進(jìn)度。比如,可以通過移動一個(gè)進(jìn)度條或者顯示一些logs在文本域。

顯示進(jìn)度的方法

4、onPostExecute

在后臺計(jì)算結(jié)束后,就會在UI線程調(diào)用onPostExecute,后臺計(jì)算的結(jié)果會作為Result類型的參數(shù)傳遞到這一步。

在構(gòu)造AsyncTask的時(shí)候,再mWorker中調(diào)用postResult來傳遞任務(wù)執(zhí)行的結(jié)果,這個(gè)結(jié)果是最后的結(jié)果了。

容錯(cuò)操作:在FutureTask中方Callable執(zhí)行完畢的時(shí)候調(diào)用done方法,在done方法里面當(dāng)任務(wù)執(zhí)行出錯(cuò),超時(shí)什么的,任務(wù)還沒執(zhí)行就down了的話,就會調(diào)用起這個(gè)方法,要是postResult成功調(diào)用了,那么這個(gè)方法就不會被調(diào)起。反正就是無論如何都要執(zhí)行postResult,代表這個(gè)任務(wù)已經(jīng)結(jié)束了。

Handler消息機(jī)制

關(guān)于Handler消息機(jī)制,大家可以去查看我之前的Handler消息機(jī)制小酌。這么就不細(xì)說了

5、取消一個(gè)任務(wù)

可以在任意時(shí)間取消一個(gè)任務(wù)通過調(diào)用cancel(boolean state),調(diào)用這個(gè)方法將會導(dǎo)致后續(xù)調(diào)用isCanceled()來判斷當(dāng)前任務(wù)狀態(tài)的時(shí)候返回true。

調(diào)用這個(gè)方法之后,任務(wù)將不會正常結(jié)束,onCanceled(Object)會代替onPostExecute被執(zhí)行,在doInBackground方法返回的時(shí)候。為了確保任務(wù)可以盡可能快地取消,應(yīng)該總是周期性地在doInBackground中檢查isCanceled()的返回值,如果可能的話設(shè)置一個(gè)循環(huán)在里面。

例子中的用法一樣

使用規(guī)則

為了使這個(gè)類能正常地使用和運(yùn)行,有幾個(gè)規(guī)則必須要遵守的:

AsyncTask類必須在UI線程中加載,在API 16中這是自動完成的,任務(wù)實(shí)例必須在UI線程創(chuàng)建,并且在UI線程調(diào)用execute方法,不要主動調(diào)用onPreExecute,doInBackground,onProgressUpdate,任務(wù)只能夠被執(zhí)行一次,如果試圖執(zhí)行第二次,那么就會拋出異常。

內(nèi)存可觀測

AsyncTask保證所有回調(diào)調(diào)用在這種方式下都是同步的,所以每一個(gè)操作都是安全的,不會出現(xiàn)多線程同時(shí)訪問的問題,不需要指定為同步:

在構(gòu)造器中或者在onPreExecute中設(shè)置成員變量,并且在doInBackground中引用他們。

在doInBackground中設(shè)置成員變量,并且在onProgressUpdate和onPostExecute中引用他們

執(zhí)行的次序

AsyncTask第一次被介紹的時(shí)候,是被連續(xù)執(zhí)行在一個(gè)單一后臺線程中的。從API4開始,改成使用一個(gè)線程池來允許多任務(wù)同步執(zhí)行。自從API 11開始,任務(wù)被執(zhí)行在一個(gè)單一的線程來避免同步執(zhí)行帶來的普通應(yīng)用錯(cuò)誤,如果你真的需要同步執(zhí)行,可以通過threadPoolExecutor調(diào)用executeOnExecutor(java.util.concurrent.Executor, Object[])來實(shí)現(xiàn)。

線程池部分

私有靜態(tài)常量(外部不可直接訪問)

CPU_COUNT:獲取當(dāng)前可用的cpu的計(jì)數(shù)。

CORE_POOL_SIZE:線程池中的核心線程數(shù)等于CPU總數(shù)加1。

MAXIMUN_POOL_SIZE:線程池中最大線程數(shù)等于CPU總數(shù)的兩倍加1。

KEEP_ALIVE:線程執(zhí)行完畢后是否維持線程。

以上的都是常量部分,用于設(shè)置默認(rèn)的線程池實(shí)現(xiàn)。用于創(chuàng)建一個(gè)ThreadPoolExecutor對象,對于這些靜態(tài)常量,同一個(gè)子類所創(chuàng)建的AsyncTask實(shí)例是共用這些對象的。就好像一開始說的,AsyncTask對象是一次性買賣。上面提到的任務(wù)池的作用就是當(dāng)我們提交多個(gè)AsyncTask實(shí)例的時(shí)候,就會進(jìn)入隊(duì)列等待了。

AsyncTask

相對于Handler,AsyncTask反而沒那么復(fù)雜了,當(dāng)然了,要是加上了線程池部分的,就復(fù)雜多了啊,不過線程池也不是一時(shí)半刻可以理完了,畢竟有了Thread才有ThreadPool嘛

說好的進(jìn)程通信呢...
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,698評論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,202評論 3 426
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,742評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,580評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,297評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,688評論 1 327
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,693評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,875評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,438評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,183評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,384評論 1 372
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,931評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,612評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,022評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,297評論 1 292
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,093評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,330評論 2 377

推薦閱讀更多精彩內(nèi)容