Android AsyncTask詳解

一配猫、Android中的線程

在操作系統(tǒng)中毛俏,線程是操作系統(tǒng)調(diào)度的最小單元炭庙,同時(shí)線程又是一種受限的系統(tǒng)資源,即線程不可能無(wú)限制地產(chǎn)生煌寇,并且**線程的創(chuàng)建和銷(xiāo)毀都會(huì)有相應(yīng)的開(kāi)銷(xiāo)焕蹄。當(dāng)系統(tǒng)中存在大量的線程時(shí),系統(tǒng)會(huì)通過(guò)會(huì)時(shí)間片輪轉(zhuǎn)的方式調(diào)度每個(gè)線程阀溶,因此線程不可能做到絕對(duì)的并行腻脏。
如果在一個(gè)進(jìn)程中頻繁地創(chuàng)建和銷(xiāo)毀線程,顯然不是高效的做法银锻。正確的做法是采用線程池永品,一個(gè)線程池中會(huì)緩存一定數(shù)量的線程,通過(guò)線程池就可以避免因?yàn)轭l繁創(chuàng)建和銷(xiāo)毀線程所帶來(lái)的系統(tǒng)開(kāi)銷(xiāo)击纬。

二鼎姐、AsyncTask簡(jiǎn)介

AsyncTask是一個(gè)抽象類(lèi),它是由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用于從工作線程切換到主線程奈惑。

1.AsyncTask的泛型參數(shù)
public abstract class AsyncTask<Params, Progress, Result>
三個(gè)泛型參數(shù)的含義分別如下:
(1)Params:開(kāi)始異步任務(wù)執(zhí)行時(shí)傳入的參數(shù)類(lèi)型;
(2)Progress:異步任務(wù)執(zhí)行過(guò)程中睡汹,返回下載進(jìn)度值的類(lèi)型肴甸;
(3)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核心方法

(1)onPreExecute()
這個(gè)方法會(huì)在后臺(tái)任務(wù)開(kāi)始執(zhí)行之間調(diào)用浮庐,在主線程執(zhí)行。用于進(jìn)行一些界面上的初始化操作柬焕,比如顯示一個(gè)進(jìn)度條對(duì)話框等审残。
(2)doInBackground(Params... 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)完成循衰。
(3)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)的更新迁酸。
(4)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ì)話框等。
上面幾個(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的簡(jiǎn)單使用

class DownloadTask extends AsyncTask<Void, Integer, Boolean> {


    private int progress=0;


    @Override  
    protected void onPreExecute() {  
        Log.e("QDTest","onPreExcute");
    }  

    @Override  
    protected Boolean doInBackground(Void... params) {  
        try {  
            while (true) {  
                int downloadPercent = doDownload();  
                publishProgress(downloadPercent);  
                if (downloadPercent >= 100) {  
                    break;  
                }  
            }  
        } catch (Exception e) {  
            return false;  
        }  
        return true;  
    }  

    @Override  
    protected void onProgressUpdate(Integer... values) {  
        //progressDialog.setMessage("當(dāng)前下載進(jìn)度:" + values[0] + "%");
        Log.e("QDTest","當(dāng)前下載進(jìn)度:" + values[0] + "%");
    }  

    @Override  
    protected void onPostExecute(Boolean result) {  
        //progressDialog.dismiss();
        Log.e("QDTest","AsyncTask運(yùn)行結(jié)束");
        if (result) {  
            //Toast.makeText(context, "下載成功", Toast.LENGTH_SHORT).show();
            Log.e("QDTest","下載成功");
        } else {  
            //Toast.makeText(context, "下載失敗", Toast.LENGTH_SHORT).show();
            Log.e("QDTest","下載失敗");
        }  
    }

    private int doDownload()
    {
        progress++;
        return progress;
    }

}

這里我們模擬了一個(gè)下載任務(wù),在doInBackground()方法中去執(zhí)行具體的下載邏輯,在onProgressUpdate()方法中顯示當(dāng)前的下載進(jìn)度萌业,在onPostExecute()方法中來(lái)提示任務(wù)的執(zhí)行結(jié)果坷襟。如果想要啟動(dòng)這個(gè)任務(wù),只需要簡(jiǎn)單地調(diào)用以下代碼即可:

new DownloadTask().execute();

4.使用AsyncTask的注意事項(xiàng)
①異步任務(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ì)拋出異常患亿。

三传蹈、AsyncTask使用不當(dāng)?shù)暮蠊?br> 1.)生命周期
AsyncTask不與任何組件綁定生命周期,所以在Activity/或者Fragment中創(chuàng)建執(zhí)行AsyncTask時(shí)步藕,最好在Activity/Fragment的onDestory()調(diào)用 cancel(boolean)惦界;

2.)內(nè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)存泄露。

3.) 結(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()再去更新界面將不再生效范删。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市拷肌,隨后出現(xiàn)的幾起案子到旦,更是在濱河造成了極大的恐慌,老刑警劉巖巨缘,帶你破解...
    沈念sama閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件添忘,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡若锁,警方通過(guò)查閱死者的電腦和手機(jī)搁骑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人仲器,你說(shuō)我怎么就攤上這事煤率。” “怎么了乏冀?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵蝶糯,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我辆沦,道長(zhǎng)昼捍,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任肢扯,我火速辦了婚禮端三,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鹃彻。我一直安慰自己郊闯,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布蛛株。 她就那樣靜靜地躺著团赁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谨履。 梳的紋絲不亂的頭發(fā)上欢摄,一...
    開(kāi)封第一講書(shū)人閱讀 51,190評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音笋粟,去河邊找鬼怀挠。 笑死,一個(gè)胖子當(dāng)著我的面吹牛害捕,可吹牛的內(nèi)容都是我干的绿淋。 我是一名探鬼主播,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼尝盼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼吞滞!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起盾沫,我...
    開(kāi)封第一講書(shū)人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤裁赠,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后赴精,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體佩捞,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年蕾哟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了一忱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片莲蜘。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖掀潮,靈堂內(nèi)的尸體忽然破棺而出菇夸,到底是詐尸還是另有隱情,我是刑警寧澤仪吧,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布庄新,位于F島的核電站,受9級(jí)特大地震影響薯鼠,放射性物質(zhì)發(fā)生泄漏择诈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一出皇、第九天 我趴在偏房一處隱蔽的房頂上張望羞芍。 院中可真熱鬧,春花似錦郊艘、人聲如沸荷科。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)畏浆。三九已至,卻和暖如春狞贱,著一層夾襖步出監(jiān)牢的瞬間刻获,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工瞎嬉, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蝎毡,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓氧枣,卻偏偏與公主長(zhǎng)得像沐兵,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子挑胸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354

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

  • 1 只有自己強(qiáng)大茬贵,才會(huì)讓你處事不驚,坐看云起移袍。 初高中時(shí)候讀武俠解藻,最喜歡讀金庸先生的作品。 坦白講葡盗,金庸小說(shuō)的男主...
    楊默閱讀 1,655評(píng)論 3 5
  • 打卡第五天 聽(tīng)了兩天最佳聲音學(xué)員的分享螟左,瑞音和艷麗姐她們共同的特點(diǎn)就是用心用腦啡浊,有學(xué)習(xí)方法,還不斷總結(jié)胶背,自我提升巷嚣,...
    bluesnow雪兒閱讀 113評(píng)論 0 0
  • 夜廷粒,莊園浴池 羽靈如往常一般半跪在我身后輕柔的為我擦拭著后背,盡管我勸阻過(guò)她回房休息红且,但是她卻堅(jiān)持要完成自己的工作...
    考拉兇猛閱讀 367評(píng)論 0 0
  • 親子日記第二十五篇 今天是開(kāi)學(xué)第一天次酌,早上起來(lái)娘倆很自覺(jué)的不懶被窩了。婆婆6點(diǎn)就開(kāi)始做飯了舆乔,我們6.30起床岳服,穿...
    一年級(jí)七班王爍樺媽媽閱讀 133評(píng)論 0 0
  • 我有兩個(gè)娃。老大是兒子蜕煌,16歲派阱;老二是閨女,十歲斜纪。為什么生孩子贫母?老實(shí)說(shuō),這個(gè)問(wèn)題我還從來(lái)沒(méi)有想過(guò)盒刚。我結(jié)婚不久就懷孕...
    小壞蛋格瑞特閱讀 1,082評(píng)論 9 6