詳細(xì)解讀AsyncTask的黑暗面以及一種替代方案

基于最新版本的AsyncTask詳細(xì)解讀主要是一些AsyncTask的原理解讀,本篇將分析AsyncTask使用的受限部,這里可能會(huì)有一些你以前沒注意到的點(diǎn),同時(shí)提供一個(gè)替代方案AsyncTaskScheduler。

一些關(guān)于AsyncTask的指責(zé)

如果搜索關(guān)鍵詞"AsyncTask的缺陷",會(huì)有很多關(guān)于AsyncTask缺陷的文章,很多是基于以下幾個(gè)問題,但這些問題真的是AsyncTask自身的問題還是使用不當(dāng)導(dǎo)致的呢?這真的需要好好分析一下,不能人云亦云,強(qiáng)行甩鍋。

  1. 生命周期和內(nèi)存泄漏
    "當(dāng)Activity結(jié)束或者退出應(yīng)用時(shí)AsyncTask會(huì)一直執(zhí)行doInBackground()方法直到方法執(zhí)行結(jié)束,這可能會(huì)導(dǎo)致在onPostExecute時(shí)view不存在而導(dǎo)致崩潰潰,以及可能的內(nèi)存泄露"。
    如果退出Activity時(shí)AsyncTask扔在執(zhí)行,上面說的的卻會(huì)發(fā)生,但這些問題需要由使用者來解決而不是AsyncTask來解決,因?yàn)锳syncTask只是執(zhí)行后臺(tái)任務(wù),它怎么知道你什么時(shí)候要終止,要退出,確定使用Handler時(shí)不會(huì)出現(xiàn)這樣問題???


    怪我嘍???

    所以應(yīng)該在相應(yīng)的生命周期如onDestory調(diào)用cancel取消任務(wù),上面的問題就不會(huì)發(fā)生了,所有這個(gè)鍋不應(yīng)該AsyncTask來背。

  2. cancel不能正常取消的問題
    首先調(diào)用cancel終止AsyncTask的原理是對(duì)執(zhí)行異步任務(wù)的線程調(diào)用interrupt()函數(shù)。
    首先,每個(gè)線程內(nèi)部都有一個(gè)boolean型變量表示線程的中斷狀態(tài),true代表線程處于中斷狀態(tài),false表示未處于中斷狀態(tài)。
    而interrupt()方法的作用只是用來改變線程的中斷狀態(tài)(把線程的中斷狀態(tài)改為true,即被中斷)。因此interrupt()方法代表著外界希望中斷此線程,只是希望,具體怎么處理還是線程內(nèi)部來做,一般情況下interrupt()方法可以使處于阻塞狀態(tài)的線程拋出InterruptedException從而結(jié)束阻塞狀態(tài)或則判斷Thread.interrupted()來處理邏輯。所以如果你的AsyncTask后臺(tái)任務(wù)有未做中斷的處理肯定會(huì)一直執(zhí)行這個(gè)線程。所以這需要你自己在doInbackground里進(jìn)行中斷處理,即使你認(rèn)為這是個(gè)缺陷也應(yīng)該是Thread類的缺陷,因?yàn)橐玫骄€程處理異步任務(wù),AsyncTask無(wú)法選擇其他方式,而且調(diào)用cancel后onPostExecute也不會(huì)在執(zhí)行了,不會(huì)導(dǎo)致UI線程的問題,所以這個(gè)鍋也不應(yīng)該AsyncTask來背。

  3. Activity意外重啟,狀態(tài)消失問題
    比如當(dāng)用戶旋轉(zhuǎn)屏幕的時(shí)候Activity就會(huì)重新啟動(dòng),如果之前有AsyncTask正在異步加載處理數(shù)據(jù),那么之前的數(shù)據(jù)就會(huì)消失,而新的AsyncTask重新創(chuàng)建,這的卻是個(gè)問題,但你用其他的方式進(jìn)行請(qǐng)求同樣會(huì)發(fā)生這個(gè)問題啊。

其實(shí)可能是我們的要求太多了,AsyncTask只是一個(gè)處理異步任務(wù)的工具,很多邏輯上的東西需要我們自己來處理,就像使用Handler和Thread,不正確處理同樣會(huì)出現(xiàn)上述問題,這些總得來說就是異步帶來的問題,這是一個(gè)時(shí)間和性能的選擇問題,AsyncTask就是簡(jiǎn)化了包裝了Handler的處理步驟而已。上面的這些更應(yīng)該是一些重要的注意事項(xiàng),而不是AsyncTask的問題

實(shí)際存在的問題

  1. 并行串行問題
    上面的一些可能是由于使用不當(dāng)導(dǎo)致的,但并行串行問題方面AsyncTask問題很大。
    使用建議

    看AsyncTask源碼文檔時(shí)看到這樣建議"AsyncTasks should ideally be used for short operations (a few seconds at the most",就是盡量執(zhí)行一個(gè)短時(shí)間的任務(wù),最對(duì)也就幾秒的任務(wù)。當(dāng)初還很疑惑,AsyncTask這玩意不就是用來處理后臺(tái)任務(wù)的嗎,又不是在主線程,為什么還限制短時(shí)間的任務(wù),那要你何用啊。
    Excuse me ? ? ?

    基于最新版本的AsyncTask詳細(xì)解讀分析過在api11后AsyncTask默認(rèn)的是串行執(zhí)行任務(wù),基本現(xiàn)上市面上的設(shè)備上都將是串行執(zhí)行。自己可以寫個(gè)Demo試試看。
    這些串行執(zhí)行共用的AsyncTask的是一個(gè)線程池,這真的很嚴(yán)重。因?yàn)槭琼樞驁?zhí)行,導(dǎo)致你調(diào)用execute() 可能 沒法立刻執(zhí)行,也可能就執(zhí)行不了,因?yàn)檎l(shuí)知道有沒有其他的AsyncTask任務(wù)在執(zhí)行啊,或者任務(wù)還是個(gè)很耗時(shí)的任務(wù),或者就是個(gè)while(ture)循環(huán)或者for(;;)來一直處理一種后臺(tái)任務(wù),那么同一進(jìn)程內(nèi)的AsyncTask在這之后調(diào)用execute的都將無(wú)法執(zhí)行。
    想當(dāng)初初學(xué)Android時(shí)覺得AsyncTask真是個(gè)方便的東西,手機(jī)寫了個(gè)基于socket通信的應(yīng)用,doInbackground處理,然后直接通知UI。在doInbackground函數(shù)里處理一些連接以及數(shù)據(jù)流的接收及發(fā)送,socket的等待連接和數(shù)據(jù)結(jié)束都是阻塞的啊,現(xiàn)在回想起來當(dāng)初真是年輕??。

當(dāng)然你可以立刻執(zhí)行一個(gè)任務(wù)通過調(diào)用executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)通過AsyncTask的THREAD_POOL_EXECUTOR線程池或者傳入其他的線程池來立刻執(zhí)行任務(wù),但THREAD_POOL_EXECUTOR有最大并發(fā)數(shù)的限制,具體分析見基于最新版本的AsyncTask詳細(xì)解讀,但只執(zhí)行一個(gè)任務(wù)時(shí)通過線程池來管理的也是無(wú)奈之舉,而且這種方式不是默認(rèn)方案啊,不一發(fā)現(xiàn)啊。

  1. 錯(cuò)誤處理問題
    AsyncTask沒有對(duì)發(fā)生的一些異常進(jìn)行處理,你只能在onBackground里進(jìn)行一些判斷,但之外的一些異常情況發(fā)生你都無(wú)法了解,比如線程異常退出等。

  2. 多個(gè)任務(wù)的管理問題
    如果需要多個(gè)后臺(tái)任務(wù),需要新建多個(gè)AsyncTask來執(zhí)行任務(wù),在需要退出的時(shí)候你需要對(duì)每一個(gè)都進(jìn)行一定的處理來避免內(nèi)存泄露以及UI問題,這是一個(gè)很麻煩的事情。

如果你使用AsyncTask默認(rèn)的執(zhí)行方式,出了問題都很難排查。你可以保證你能正確使用AsyncTask,但你沒法保證別人也能正確使用啊,這就是別人給你挖的坑,但是你跳了進(jìn)去啊,關(guān)鍵你可能都不知道到底哪個(gè)AsyncTask在執(zhí)行,可能引用就發(fā)生在第三方庫(kù)的也有可能啊。

替代方案

基于上述實(shí)際存在的問題尤其是并行串行問題,寫了一個(gè)類似AsyncTask的庫(kù)AsyncTaskScheduler,處理了上述的一些實(shí)際存在的問題。
細(xì)節(jié)介紹及使用

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容