Android 中糟糕的AsyncTask
AsyncTask是一個(gè)很常用的API,尤其異步處理數(shù)據(jù)并將數(shù)據(jù)應(yīng)用到視圖的操作場(chǎng)合。其實(shí)AsyncTask并不是那么好,甚至有些糟糕。本文我會(huì)講AsyncTask會(huì)引起哪些問(wèn)題,如何修復(fù)這些問(wèn)題,并且關(guān)于AsyncTask的一些替代方案。
AsyncTask
從Android API 3(1.5 Cupcake)開(kāi)始,AsyncTask被引入用來(lái)幫助開(kāi)發(fā)者更簡(jiǎn)單地管理線程。實(shí)際上在Android 1.0和1.1也是有類似的實(shí)現(xiàn),那就是UserTask。UserTask和AsyncTask有著相同的API及實(shí)現(xiàn),但是由于由于1.0和1.1的設(shè)備份額微乎其微,這里的概念就不會(huì)涉及到UserTask。
生命周期
關(guān)于AsyncTask存在一個(gè)這樣廣泛的誤解,很多人認(rèn)為一個(gè)在Activity中的AsyncTask會(huì)隨著Activity的銷毀而銷毀。然后事實(shí)并非如此。AsyncTask會(huì)一直執(zhí)行doInBackground()方法直到方法執(zhí)行結(jié)束。一旦上述方法結(jié)束,會(huì)依據(jù)情況進(jìn)行不同的操作。
如果cancel(boolean)調(diào)用了,則執(zhí)行onCancelled(Result)方法
如果cancel(boolean)沒(méi)有調(diào)用,則執(zhí)行onPostExecute(Result)方法
AsyncTask的cancel方法需要一個(gè)布爾值的參數(shù),參數(shù)名為mayInterruptIfRunning,意思是如果正在執(zhí)行是否可以打斷,如果這個(gè)值設(shè)置為true,表示這個(gè)任務(wù)可以被打斷,否則,正在執(zhí)行的程序會(huì)繼續(xù)執(zhí)行直到完成。如果在doInBackground()方法中有一個(gè)循環(huán)操作,我們應(yīng)該在循環(huán)中使用isCancelled()來(lái)判斷,如果返回為true,我們應(yīng)該避免執(zhí)行后續(xù)無(wú)用的循環(huán)操作。
總之,我們使用AsyncTask需要確保AsyncTask正確地取消。
不好好工作的cancel()
簡(jiǎn)而言之的答案,有時(shí)候起作用。
如果你調(diào)用了AsyncTask的cancel(false),doInBackground()仍然會(huì)執(zhí)行到方法結(jié)束,只是不會(huì)去調(diào)用onPostExecute()方法。但是實(shí)際上這是讓?xiě)?yīng)用程序執(zhí)行了沒(méi)有意義的操作。那么是不是我們調(diào)用cancel(true)前面的問(wèn)題就能解決呢?并非如此。如果mayInterruptIfRunning設(shè)置為true,會(huì)使任務(wù)盡早結(jié)束,但是如果的doInBackground()有不可打斷的方法會(huì)失效,比如這個(gè)BitmapFactory.decodeStream() IO操作。但是你可以提前關(guān)閉IO流并捕獲這樣操作拋出的異常。但是這樣會(huì)使得cancel()方法沒(méi)有任何意義。
內(nèi)存泄露
還有一種常見(jiàn)的情況就是,在Activity中使用非靜態(tài)匿名內(nèi)部AsyncTask類,由于Java內(nèi)部類的特點(diǎn),AsyncTask內(nèi)部類會(huì)持有外部類的隱式引用。詳細(xì)請(qǐng)參考細(xì)話Java:”失效”的private修飾符,由于AsyncTask的生命周期可能比Activity的長(zhǎng),當(dāng)Activity進(jìn)行銷毀AsyncTask還在執(zhí)行時(shí),由于AsyncTask持有Activity的引用,導(dǎo)致Activity對(duì)象無(wú)法回收,進(jìn)而產(chǎn)生內(nèi)存泄露。
結(jié)果丟失
另一個(gè)問(wèn)題就是在屏幕旋轉(zhuǎn)等造成Activity重新創(chuàng)建時(shí)AsyncTask數(shù)據(jù)丟失的問(wèn)題。當(dāng)Activity銷毀并創(chuàng)新創(chuàng)建后,還在運(yùn)行的AsyncTask會(huì)持有一個(gè)Activity的非法引用即之前的Activity實(shí)例。導(dǎo)致onPostExecute()沒(méi)有任何作用。
串行還是并行
關(guān)于AsyncTask時(shí)串行還是并行有很多疑問(wèn),這很正常,因?yàn)樗?jīng)過(guò)多次的修改。如果你并不明白什么時(shí)串行還是并行,可以通過(guò)接下來(lái)的例子了解,假設(shè)我們?cè)谝粋€(gè)方法體里面有如下兩行代碼
new AsyncTask1().execute();
new AsyncTask2().execute();
上面的兩個(gè)任務(wù)時(shí)同時(shí)執(zhí)行呢,還是AsyncTask1執(zhí)行結(jié)束之后,AsyncTask2才能執(zhí)行呢?實(shí)際上是結(jié)果依據(jù)API不同而不同。
在1.6(Donut)之前:
在第一版的AsyncTask,任務(wù)是串行調(diào)度。一個(gè)任務(wù)執(zhí)行完成另一個(gè)才能執(zhí)行。由于串行執(zhí)行任務(wù),使用多個(gè)AsyncTask可能會(huì)帶來(lái)有些問(wèn)題。所以這并不是一個(gè)很好的處理異步(尤其是需要將結(jié)果作用于UI試圖)操作的方法。
從1.6到2.3(Gingerbread)
后來(lái)Android團(tuán)隊(duì)決定讓AsyncTask并行來(lái)解決1.6之前引起的問(wèn)題,這個(gè)問(wèn)題是解決了,新的問(wèn)題又出現(xiàn)了。很多開(kāi)發(fā)者實(shí)際上依賴于順序執(zhí)行的行為。于是很多并發(fā)的問(wèn)題蜂擁而至。
3.0(Honeycomb)到現(xiàn)在
好吧,開(kāi)發(fā)者可能并不喜歡讓AsyncTask并行,于是Android團(tuán)隊(duì)又把AsyncTask改成了串行。當(dāng)然這一次的修改并沒(méi)有完全禁止AsyncTask并行。你可以通過(guò)設(shè)置executeOnExecutor(Executor)來(lái)實(shí)現(xiàn)多個(gè)AsyncTask并行。關(guān)于API文檔的描述如下
If we want to make sure we have control over the execution, whether it will run serially or parallel, we can check at runtime with this code to make sure it runs parallel:
public static void execute(AsyncTask as) { if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB_MR1) { as.execute(); } else { as.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } } //(This code does not work for API lvl 1 to 3)
真的需要AsyncTask么
并非如此,使用AsyncTask雖然可以以簡(jiǎn)短的代碼實(shí)現(xiàn)異步操作,但是正如本文提到的,你需要讓AsyncTask正常工作的話,需要注意很多條條框框。推薦的一種進(jìn)行異步操作的技術(shù)就是使用Loaders。這個(gè)方法從Android 3.0 (Honeycomb)開(kāi)始引入,在android支持包中也有包含??梢酝ㄟ^(guò)查看官方的文檔來(lái)詳細(xì)了解Loaders。
本次譯文對(duì)原文有少部分刪減修改處理。
以上就是對(duì)Android AsyncTsak 的資料整理,后繼續(xù)補(bǔ)充相關(guān)資料,謝謝大家對(duì)本站的支持!
- 詳解Android中AsyncTask的使用方法
- Android利用AsyncTask異步類實(shí)現(xiàn)網(wǎng)頁(yè)內(nèi)容放大縮小
- Android中通過(guò)AsyncTask類來(lái)制作炫酷進(jìn)度條的實(shí)例教程
- 詳解Android App中的AsyncTask異步任務(wù)執(zhí)行方式
- Android使用AsyncTask實(shí)現(xiàn)多線程下載的方法
- Android中AsyncTask異步任務(wù)使用詳細(xì)實(shí)例(一)
- Android 中使用 AsyncTask 異步讀取網(wǎng)絡(luò)圖片
- 詳解Android中AsyncTask機(jī)制
- Android通過(guò)Handler與AsyncTask兩種方式動(dòng)態(tài)更新ListView(附源碼)
- Android中AsyncTask與handler用法實(shí)例分析
- Android AsyncTask 后監(jiān)聽(tīng)異步加載完畢的動(dòng)作詳解
相關(guān)文章
Android 實(shí)現(xiàn)調(diào)用系統(tǒng)照相機(jī)拍照和錄像的功能
這篇文章主要介紹了Android 實(shí)現(xiàn)調(diào)用系統(tǒng)照相機(jī)拍照和錄像的功能的相關(guān)資料,需要的朋友可以參考下2016-11-11Android中關(guān)于CoordinatorLayout的一些實(shí)用布局技巧
大家都知道CoordinatorLayout是一個(gè)“加強(qiáng)版”的 FrameLayout,那么下面這篇文章主要給大家分享了Android中關(guān)于CoordinatorLayout的一些布局技巧,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-06-06Android編程基于Contacts讀取聯(lián)系人的方法(附demo源碼)
這篇文章主要介紹了Android編程基于Contacts讀取聯(lián)系人的方法,實(shí)例分析了Contacts讀取的實(shí)現(xiàn)方法及權(quán)限設(shè)置方法,并附帶了完整實(shí)例供讀者下載參考,需要的朋友可以參考下2015-12-12Android編程實(shí)現(xiàn)的短信編輯器功能示例
這篇文章主要介紹了Android編程實(shí)現(xiàn)的短信編輯器功能,涉及Android權(quán)限控制、界面布局及短信功能相關(guān)操作技巧,需要的朋友可以參考下2017-08-08Android 自定義組件衛(wèi)星菜單的實(shí)現(xiàn)
這篇文章主要介紹了Android 自定義組件衛(wèi)星菜單的實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2017-07-07Android中標(biāo)簽容器控件的實(shí)例詳解
在Android開(kāi)發(fā)過(guò)程中,常常會(huì)遇到這樣的場(chǎng)景:我們展示一種物品或者為某一事物添加一些標(biāo)簽。比如說(shuō),我們買一件衣服,可以有以下幾種標(biāo)簽:杰克瓊斯,男士,運(yùn)動(dòng)等等。本文將實(shí)例介紹Android中標(biāo)簽容器控件的實(shí)現(xiàn)過(guò)程。2016-07-07Android編程實(shí)現(xiàn)攔截短信并屏蔽系統(tǒng)Notification的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)攔截短信并屏蔽系統(tǒng)Notification的方法,較為詳細(xì)的分析了Android短信與Notification的原理及對(duì)應(yīng)的設(shè)置取消技巧,需要的朋友可以參考下2015-12-12Android發(fā)布項(xiàng)目到j(luò)itpack的完整步驟
這篇文章主要給大家介紹了關(guān)于Android發(fā)布項(xiàng)目到j(luò)itpack的完整步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-01-01android RecycleView實(shí)現(xiàn)多級(jí)樹(shù)形列表
這篇文章主要為大家詳細(xì)介紹了android RecycleView實(shí)現(xiàn)多級(jí)樹(shù)形列表,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05