最近寫一個android小應(yīng)用曾棕,用到了AsyncTask發(fā)現(xiàn)一些問題油昂,寫篇日志避免日后再犯相同的錯誤,也給遇到與我
相同問題和疑惑的小伙伴們點思路毕荐。
AsyncTask的基本使用方法這里不再贅述束析,直接切入主題。
我用的SDK4.0东跪,代碼(片段)如下:
[java]view plaincopy
packagecom.lic.centerctrl;
importjava.util.HashMap;
importjava.util.Map;
importjava.util.concurrent.ExecutorService;
importjava.util.concurrent.Executors;
importcom.lic.activity.ActivityInterFace;
importandroid.app.Activity;
importandroid.app.Service;
importandroid.content.Context;
importandroid.content.Intent;
importandroid.os.AsyncTask;
importandroid.os.IBinder;
publicclassMainServiceextendsService{
privatestaticTask?task;//當(dāng)前執(zhí)行任務(wù)
privatestaticMap?allActivitys?=newHashMap();//緩存activity集合
privatestaticExecutorService?exec?=?Executors.newSingleThreadExecutor();
@Override
publicvoidonStart(Intent?intent,intstartId)?{
super.onStart(intent,?startId);
MainAsyncTask?asyncTask?=newMainAsyncTask();
//asyncTask.execute(task);
//asyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR,?task);
//asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,?task);
//asyncTask.executeOnExecutor(Executors.newFixedThreadPool(2),?task);
asyncTask.executeOnExecutor(exec,?task);
}
privatefinalclassMainAsyncTaskextendsAsyncTask{
privateTask?task;
@Override
protectedObject?doInBackground(Object...?params)?{
Object?result?=null;
task?=?(Task)params[0];
switch(task.getTaskID())?{
caseTask.TASK_USER_LOGIN:
try{
Thread.sleep(3000);
System.out.println("任務(wù)"+task.getTaskID()+"?Thread?id:?"+Thread.currentThread().getId());
}catch(InterruptedException?e)?{
e.printStackTrace();
}
break;
case2:
System.out.println("任務(wù)"+task.getTaskID()+"?Thread?id:?"+Thread.currentThread().getId());
break;
}
returnresult;
}
@Override
protectedvoidonPostExecute(Object?result)?{
super.onPostExecute(result);
ActivityInterFace?aif;
switch(task.getTaskID())?{
caseTask.TASK_USER_LOGIN:
aif?=?(ActivityInterFace)allActivitys.get("LoginActivity");
aif.refresh(1,?result);
break;
case2:
aif?=?(ActivityInterFace)allActivitys.get("LoginActivity");
aif.refresh(2,?result);
break;
default:
break;
}
}
}
/**
*?添加新任務(wù)
*?@param?task
*/
publicstaticvoidaddTask(Context?context,?Task?task)?{
MainService.task?=?task;
context.startService(newIntent("mainService"));
}
/**
*?緩存activity
*?@param?activity
*/
publicstaticvoidaddActivity(Activity?activity)?{
String?path?=?activity.getClass().getName();
String?name?=?path.substring(path.lastIndexOf(".")+1);
allActivitys.put(name,?activity);
}
@Override
publicIBinder?onBind(Intent?intent)?{
returnnull;
}
}
當(dāng)我執(zhí)行兩次調(diào)用asyncTask.execute(task);時發(fā)現(xiàn)只有當(dāng)?shù)谝淮蔚娜蝿?wù)完成后才執(zhí)行下一下任務(wù)!鹰溜!怎么回事虽填?
AyncTask不是號稱異步線程池嗎?既然是線程池那么多任務(wù)執(zhí)行時應(yīng)該可以并發(fā)執(zhí)行啊曹动,至少兩個任務(wù)可以并發(fā)執(zhí)
行斋日,以前看過一個視頻,人家的就可以澳钩隆恶守!糾結(jié)了一下午,通過查閱資料和自己的動手實驗終于把問題搞明白了贡必。
原來在SDK3.0以前的版本執(zhí)行asyncTask.execute(task);時的確是多線程并發(fā)執(zhí)行的兔港,線程池大小為5,最大可大
128個仔拟,google在3.0以后的版本中做了修改衫樊,將asyncTask.execute(task);修改為了順序執(zhí)行,即只有當(dāng)一個的實例
的任務(wù)完成后在執(zhí)行下一個實例的任務(wù)利花。
那么怎么才能并發(fā)執(zhí)行呢科侈,很簡單,3.0后新增了一個方法executeOnExecutor(Executorexec,Object... params)炒事,
該方法接受2個參數(shù)臀栈,第一個是Executor,第二個是任務(wù)參數(shù)挠乳。第一個是線程池實例权薯,google為我們預(yù)定義了兩種:
第一種是AsyncTask.SERIAL_EXECUTOR姑躲,第二種是AsyncTask.THREAD_POOL_EXECUTOR,顧名思義崭闲,第一
種其實就像3.0以后的execute方法肋联,是順序執(zhí)行的。第二種就是3.0以前的execute方法刁俭,是可以并發(fā)執(zhí)行的橄仍。我們直
接用asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, task);就可以多任務(wù)并發(fā)執(zhí)行了。
既然executeOnExecutor第一個參數(shù)是Executor牍戚,那么我們可以自定義Executor嗎侮繁?當(dāng)然可以,Executor主要由四
種類型newCachedThreadPool如孝,newFixedThreadPool宪哩,newScheduledThreadPool,newSingleThreadExecutor
(具體使用解析可以看我上一篇文章點擊打開鏈接)第晰,可是當(dāng)我這樣使用
asyncTask.executeOnExecutor(Executors.newFixedThreadPool(1), task);或者
asyncTask.executeOnExecutor(Executors.newSingleThreadExecutor, task);并沒有像我想象的與
asyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, task);那樣是單線程順序執(zhí)行锁孟,而是像
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, task);是多線程并發(fā)執(zhí)行的,我不是
已經(jīng)規(guī)定newFixedThreadPool的線程池數(shù)量是1或者是newSingleThreadExecutor單線程了么茁瘦!怎么回事呢品抽?原來程
序在每次調(diào)用asyncTask.executeOnExecutor(Executors.newFixedThreadPool(2), task)時會獲取一個新的Executor對
象,這個對象內(nèi)的線程只執(zhí)行對應(yīng)的task甜熔,所以無論哪種情況每個task都有一個新的線程來執(zhí)行圆恤,即并發(fā)執(zhí)行。
知道原因就好辦了腔稀,我們定義個一全局靜態(tài)變量
private static ExecutorService exec = Executors.newSingleThreadExecutor();程序在每次調(diào)用
asyncTask.executeOnExecutor(exec, task);時是使用的同一個Executor盆昙,執(zhí)行效果如下:
當(dāng)Executor類型為:private static ExecutorService exec = Executors.newFixedThreadPool(2);只有兩個線程在執(zhí)行
任務(wù)
當(dāng)Executor類型為:private static ExecutorService exec = Executors.newSingleThreadExecutor();只有一個線程在執(zhí)行任務(wù)