最近寫一個(gè)android小應(yīng)用,用到了AsyncTask發(fā)現(xiàn)一些問題,寫篇日志避免日后再犯相同的錯(cuò)誤,也給遇到與我
相同問題和疑惑的小伙伴們點(diǎ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);時(shí)發(fā)現(xiàn)只有當(dāng)?shù)谝淮蔚娜蝿?wù)完成后才執(zhí)行下一下任務(wù)!!怎么回事?
AyncTask不是號(hào)稱異步線程池嗎?既然是線程池那么多任務(wù)執(zhí)行時(shí)應(yīng)該可以并發(fā)執(zhí)行啊,至少兩個(gè)任務(wù)可以并發(fā)執(zhí)
行,以前看過一個(gè)視頻,人家的就可以啊!糾結(jié)了一下午,通過查閱資料和自己的動(dòng)手實(shí)驗(yàn)終于把問題搞明白了。
原來在SDK3.0以前的版本執(zhí)行asyncTask.execute(task);時(shí)的確是多線程并發(fā)執(zhí)行的,線程池大小為5,最大可大
128個(gè),google在3.0以后的版本中做了修改,將asyncTask.execute(task);修改為了順序執(zhí)行,即只有當(dāng)一個(gè)的實(shí)例
的任務(wù)完成后在執(zhí)行下一個(gè)實(shí)例的任務(wù)。
那么怎么才能并發(fā)執(zhí)行呢,很簡(jiǎn)單,3.0后新增了一個(gè)方法executeOnExecutor(Executorexec,Object... params),
該方法接受2個(gè)參數(shù),第一個(gè)是Executor,第二個(gè)是任務(wù)參數(shù)。第一個(gè)是線程池實(shí)例,google為我們預(yù)定義了兩種:
第一種是AsyncTask.SERIAL_EXECUTOR,第二種是AsyncTask.THREAD_POOL_EXECUTOR,顧名思義,第一
種其實(shí)就像3.0以后的execute方法,是順序執(zhí)行的。第二種就是3.0以前的execute方法,是可以并發(fā)執(zhí)行的。我們直
接用asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, task);就可以多任務(wù)并發(fā)執(zhí)行了。
既然executeOnExecutor第一個(gè)參數(shù)是Executor,那么我們可以自定義Executor嗎?當(dāng)然可以,Executor主要由四
種類型newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor
(具體使用解析可以看我上一篇文章點(diǎn)擊打開鏈接),可是當(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的線程池?cái)?shù)量是1或者是newSingleThreadExecutor單線程了么!怎么回事呢?原來程
序在每次調(diào)用asyncTask.executeOnExecutor(Executors.newFixedThreadPool(2), task)時(shí)會(huì)獲取一個(gè)新的Executor對(duì)
象,這個(gè)對(duì)象內(nèi)的線程只執(zhí)行對(duì)應(yīng)的task,所以無論哪種情況每個(gè)task都有一個(gè)新的線程來執(zhí)行,即并發(fā)執(zhí)行。
知道原因就好辦了,我們定義個(gè)一全局靜態(tài)變量
private static ExecutorService exec = Executors.newSingleThreadExecutor();程序在每次調(diào)用
asyncTask.executeOnExecutor(exec, task);時(shí)是使用的同一個(gè)Executor,執(zhí)行效果如下:
當(dāng)Executor類型為:private static ExecutorService exec = Executors.newFixedThreadPool(2);只有兩個(gè)線程在執(zhí)行
任務(wù)
當(dāng)Executor類型為:private static ExecutorService exec = Executors.newSingleThreadExecutor();只有一個(gè)線程在執(zhí)行任務(wù)
