一、AsyncTask的簡(jiǎn)介
AsyncTask是一個(gè)抽象泛型類嗤堰,它是由Android封裝的輕量級(jí)異步類(使用方便、代碼簡(jiǎn)介)钱磅,它可以在線程中執(zhí)行后臺(tái)任務(wù),然后將執(zhí)行的結(jié)果以及進(jìn)度傳遞給主線程似枕,并在主線程更新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 用于線程的切換毅往,從工作線程切換到主線程。
二派近、AsyncTask的泛型參數(shù)
public abstract class AsyncTask<Params, Progress, Result>
Params:開始異步任務(wù)時(shí)傳入的參數(shù)類型攀唯,在execute()傳入,跟doInBackground(Void... params)里的params類型一樣渴丸。
Progress:執(zhí)行進(jìn)度侯嘀,跟onProgressUpdate(Integer... values)的values類型一致,一般情況為Integer谱轨。
Result:執(zhí)行結(jié)束的返回值戒幔,跟doInBackground返回的參數(shù)類型一致,并且跟onPostExecute的參數(shù)一致土童。
如果AsyncTask確定不需要傳遞具體的參數(shù)诗茎,那么這三個(gè)泛型參數(shù)可以用Void代替。
三献汗、AsyncTask的核心方法
onPreExecute()
- 后臺(tái)任務(wù)開始執(zhí)行之前調(diào)用敢订,在主線程調(diào)用,用來(lái)進(jìn)行一些界面的初始化操作罢吃,如顯示一個(gè)進(jìn)度條對(duì)話框楚午。
doInBackground(Params...)
這個(gè)方法的所有代碼都在子線程中執(zhí)行,我們應(yīng)該在這里去處理所有的耗時(shí)操作尿招。
這個(gè)方法不可以進(jìn)行UI操作矾柜,如果需要更新UI,如反饋進(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ù)的值對(duì)界面元素進(jìn)行相應(yīng)更新捆愁。
onPostExecute(Result)
當(dāng)doInBackground(Params...)執(zhí)行完并通過(guò)return語(yǔ)句進(jìn)行返回時(shí)割去,這個(gè)方法就會(huì)被調(diào)用。
返回的數(shù)據(jù)會(huì)作為參數(shù)傳遞到該方法中昼丑,可進(jìn)行一寫UI操作呻逆,提醒、關(guān)閉進(jìn)度框之類的菩帝。
上述方法執(zhí)行順序:
onPreExecute() --> doInBackground() --> publishProgress() --> onProgressUpdate() --> onPostExecute()
如果不需要執(zhí)行更新進(jìn)度咖城,則:
onPreExecute() --> doInBackground() --> onPostExecute()
AsyncTask還提供了cancel(boolean)方法,用于取消異步任務(wù)呼奢,在主線程中調(diào)用宜雀。當(dāng)cancel(boolean)被調(diào)用時(shí),onPostExecute()則不被調(diào)用握础,將會(huì)調(diào)用onCancelled()方法辐董。但并不是真正的取消任務(wù),只是設(shè)置了這個(gè)任務(wù)為取消狀態(tài)禀综,我們需要在doInBackground()判斷終止任務(wù)简烘。
四、AsyncTask的簡(jiǎn)單使用
class DownloadTask extends AsyncTask<Void, Integer, Boolean> {
@Override
protected void onPreExecute() {
progressDialog.show();
}
@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] + "%");
}
@Override
protected void onPostExecute(Boolean result) {
progressDialog.dismiss();
if (result) {
Toast.makeText(context, "下載成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "下載失敗", Toast.LENGTH_SHORT).show();
}
}
}
這里模仿下載任務(wù)定枷,doInBackground()執(zhí)行下載邏輯孤澎,onProgressUpdate()顯示當(dāng)前下載進(jìn)度,onPostExecute()提示任務(wù)執(zhí)行結(jié)果欠窒。
如果啟動(dòng)任務(wù)覆旭,只需調(diào)用以下代碼:
new DownloadTask().execute();
五、AsyncTask的使用注意事項(xiàng)
異步任務(wù)的實(shí)例必須在UI線程創(chuàng)建贱迟,即AsyncTask對(duì)象必須在UI線程創(chuàng)建姐扮。
execute()、cancelled()方法必須在UI線程調(diào)用衣吠。
不能在doInBackground()方法中更新UI茶敏。
一個(gè)任務(wù)實(shí)例只能執(zhí)行一次,如果執(zhí)行第二次會(huì)拋異常缚俏。
六惊搏、AsyncTask的缺陷
生命周期:
- AsyncTask不與任何組件綁定生命周期,所以在Activity或者Fragment創(chuàng)建AsyncTask時(shí)忧换,最好在onDestory()調(diào)用cancel(boolean)方法恬惯。總之我們要確保正確的取消AsyncTask亚茬。
內(nèi)存泄漏:
- 如果AsyncTask被聲明為Activity的非靜態(tài)內(nèi)部類酪耳,那么AsyncTask會(huì)保留一個(gè)對(duì)創(chuàng)建Activity的引用。如果Activity已經(jīng)被銷毀,AsyncTask還在后臺(tái)執(zhí)行碗暗,它將繼續(xù)在內(nèi)存保留這個(gè)引用颈将,導(dǎo)致Activity無(wú)法被回收,引起內(nèi)存泄漏言疗。
cancel(boolean)不一定好使:
- 當(dāng)AsyncTask已經(jīng)完成晴圾,亦或其他原因不能被取消,調(diào)用cancel(boolean)并沒有實(shí)際效果噪奄,還是會(huì)繼續(xù)執(zhí)行doInBackground()方法死姚,只是不執(zhí)行onPostExecute()。
boolean參數(shù)mayInterruptIfRunning決定是否立即stop該Task
結(jié)果丟失:
- 屏幕旋轉(zhuǎn)或者Activity在后臺(tái)被系統(tǒng)殺掉等情況勤篮,會(huì)導(dǎo)致Activity的重新創(chuàng)建都毒,之前運(yùn)行的AsyncTask(非靜態(tài)內(nèi)部類的)會(huì)持有之前Activity的引用,但這個(gè)引用已經(jīng)無(wú)效叙谨,這時(shí)調(diào)用onPostExecute()再去更新UI將不再有效温鸽。
串行還是并行:
- AsyncTask默認(rèn)串行執(zhí)行保屯,也可以通過(guò)設(shè)置executeOnExecutor(Executor)來(lái)實(shí)現(xiàn)多個(gè)AsyncTask并行手负。
七、AsyncTask與Handler的關(guān)系
它們的關(guān)系并不大姑尺,甚至可以說(shuō)不是一個(gè)層面的東西竟终,因?yàn)锳syncTask本質(zhì)是對(duì)Handler的封裝,并且內(nèi)部有自己維護(hù)的線程池切蟋。
有一些相同的目的统捶,都可以異步執(zhí)行一些代碼,避免阻塞UI線程柄粹。
至于AsyncTask的源碼理解喘鸟,等以后理解了,再補(bǔ)上驻右,再次留下了沒技術(shù)的眼淚~
最后奉上參考博文什黑,畢竟東拼西湊(捂臉):
Android中的線程狀態(tài)之AsyncTask詳解
AsyncTask 使用和缺陷