注意事項:
- 參數(shù):
AsyncTask<Params,Progress,Result>:Void,Integer卫玖,String稳析,Object等,可以使任意類型或封裝的對象燎竖。
AsyncTask定義了三種泛型類型 Params,Progress和Result要销。
Params 啟動任務(wù)執(zhí)行的輸入?yún)?shù)--execute()中傳入的參數(shù)构回。
Progress 后臺任務(wù)執(zhí)行的進(jìn)度--publishProgress中傳入的參數(shù),onProgressUpdate中接收的參數(shù)蕉陋。
Result 后臺執(zhí)行任務(wù)最終返回的結(jié)果--例如:doInBackgroud中返回的boolean判斷執(zhí)行是否成功捐凭。
- 不能在子線程生成Async實例
ASync中的Handler為靜態(tài)變量,類加載的時候生成凳鬓,如果在子線程中new Async茁肠,那么Handler也會new,此時子線程new Handler之前沒有prepeare會報錯缩举。
- execute只能在UI線程調(diào)用垦梆?
如果onPreExecute沒有操作UI,其實也是可以的調(diào)用的仅孩。
- AsyncTask是串行執(zhí)行的托猩,多個任務(wù)執(zhí)行的時候一個一個等待。但是注意辽慕,每次execute操作京腥,將任務(wù)封裝放入隊列,無論是等待還是執(zhí)行溅蛉,在execute的時候公浪,就馬上調(diào)用onPreExecute了他宛。有可能該任務(wù)需要等待,但是該任務(wù)下的onPreExecute方法已經(jīng)執(zhí)行了欠气。
- AsyncTask默認(rèn)是串行的厅各,也可以并行操作
mAsyncTask = new MyAsyncTask(myCount);
mAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,myCount+"");
"AsyncTask并不適合進(jìn)行特別耗時的后臺任務(wù),對特別耗時的任務(wù)预柒,建議使用線程池队塘。--開發(fā)藝術(shù)探索上所寫,但是還并未理解"
可能是因為:多個任務(wù)時特別耗時的任務(wù)會影響后面的任務(wù)遲遲不能執(zhí)行宜鸯。用線程池并發(fā)的話憔古,就沒這樣的問題了。
- 一個AsyncTask對象顾翼,只能執(zhí)行一次execute投放,前面分析源碼的時候已經(jīng)驗證過了奈泪,Running或者Finished的時候再執(zhí)行都會報錯适贸。
- 無論在任何線程,任何地方使用AsyncTask涝桅,因為該類內(nèi)部的sDefaultExecutor是static類型拜姿,都將只有一個線程池對象。所以冯遂,AsyncTask的任務(wù)都是在這一個線程池中執(zhí)行蕊肥。
所以,任何線程蛤肌,任何地方壁却,單次或多次調(diào)用AsyncTask執(zhí)行,都是會放入隊列裸准,串行執(zhí)行的展东。
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
AsyncTask 缺陷/坑:
AsyncTask有多個版本,多種實現(xiàn)炒俱,不具體分析盐肃。
總之,在3.0以前权悟,最大支持128個線程的并發(fā)砸王,10個任務(wù)的等待。并發(fā)執(zhí)行峦阁,不用等待谦铃。超過138個任務(wù)同時執(zhí)行,會發(fā)生異常:java.util.concurrent.RejectedExecutionException 榔昔。
在3.0以后驹闰,無論有多少任務(wù)凿跳,都會在其內(nèi)部單線程一個一個執(zhí)行;異常問題:
Activity退出時疮方,記得在onDestroy中cancle控嗜,并在AsyncTask做isCancel檢查操作,確定Async代碼是否執(zhí)行骡显。否則疆栏,有坑能退出Activity的時候Async還沒有執(zhí)行完,Async執(zhí)行完要更新UI的時候View已經(jīng)銷毀惫谤。
- 內(nèi)存泄漏問題:
1.Java特性壁顶,AsyncTask類在Activity是非靜態(tài)內(nèi)部類的時候,默認(rèn)持有外部類Activity的引用溜歪。
2.AsyncTask持有Activity中的變量若专,如View。
如何避免:
靜態(tài)內(nèi)部類蝴猪。activity若引用调衰,使用activity變量的時候判斷null。例如前篇自阱,Handler防止內(nèi)存泄漏一樣嚎莉。
取消操作任務(wù)操作時,AsyncTask不能中斷的處理沛豌。
cancel的時候趋箩,并不能中斷已經(jīng)開始的任務(wù),因為不能中斷正在執(zhí)行的Thread(但是測試的可以中斷正在執(zhí)行的Async加派,看下面"不確定"叫确,這里就按大部分人說的不能中斷的情況下)。
//AsyncTask方法
public final boolean cancel(boolean mayInterruptIfRunning) {
//標(biāo)記
mCancelled.set(true);
return mFuture.cancel(mayInterruptIfRunning);
}
//FutureTask方法
public boolean cancel(boolean mayInterruptIfRunning) {
if (!(state == NEW &&
U.compareAndSwapInt(this, STATE, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null)
//中斷子線程芍锦。應(yīng)該是不能中斷的竹勉,但是測試是可以中斷的。
t.interrupt();
} finally { // final state
U.putOrderedInt(this, STATE, INTERRUPTED);
}
}
} finally {
//最后調(diào)用onCancle()方法
finishCompletion();
}
return true;
}
mCancelled.set(true);只是在AsyncTask中一個標(biāo)記醉旦,說明是否執(zhí)行過中斷操作饶米,至于有沒有中斷成功isCancelled()的返回值并不能說明。 t.interrupt();才是執(zhí)行中斷線程的主要代碼车胡,現(xiàn)在并不確定該方法是否能中斷線程(網(wǎng)上說不能中斷檬输,而我測試可以中斷)。
解決辦法:
- 在AsyncTask執(zhí)行的代碼中匈棘,判斷是否中斷丧慈,isCancelled();
- 如果后臺任務(wù)有頻繁的while操作,可以添加Thread.sleep(1)。因為interrupt的時候逃默,會使阻塞的線程拋異常鹃愤,捕獲異常后return結(jié)束doInBackgroud方法。
不確定:
- 中斷任務(wù):
Thread/AsyncTask不能中斷完域。Java線程在執(zhí)行的時候软吐,并不能中斷該線程,同樣AsyncTask也是吟税。但是測試的結(jié)果是凹耙,Thread不能中斷,AsyncTask可以中斷肠仪。
按說肖抱,它們都是把執(zhí)行的代碼封裝到了Runnable,開子線程執(zhí)行异旧。但測試就是Thread中斷了意述,AsyncTask沒有中斷。
//testThread.interrupt();不能中斷
public class TestRunnable implements Runnable {
private static final String TAG = "TestRunnable";
private int count = 0;
@Override
public void run() {
while (count < 1000) {
Log.e(TAG, "run: count=" + count);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
//interrupt會使阻塞的線程拋該異常吮蛹。也可以利用這個特性荤崇,中斷任務(wù)。拋異常的時候return匹涮。
// return;
}
count++;
}
}
}
// mAsyncTask.execute(count + ""); 按說也因該不能中斷的天试,但是槐壳,測試的時候就是中斷了啊然低。
@Override
protected Boolean doInBackground(String... params) {
while (currentProgress <= 100) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
//return false;
}
currentProgress++;
}
return true;
}