转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/17596225

前言

什么是AsyncTask,相信搞过android开发的朋友们都不陌生。AsyncTask内部封装了Thread和Handler,可以让我们在后台进行计算并且把计算的结果及时更新到UI上,而这些正是Thread+Handler所做的事情,没错,AsyncTask的作用就是简化Thread+Handler,让我们能够通过更少的代码来完成一样的功能,这里,我要说明的是:AsyncTask只是简化Thread+Handler而不是替代,实际上它也替代不了。同时,AsyncTask从最开始到现在已经经过了几次代码修改,任务的执行逻辑慢慢地发生了改变,并不是大家所想象的那样:AsyncTask是完全并行执行的就像多个线程一样,其实不是的,所以用AsyncTask的时候还是要注意,下面会一一说明。另外本文主要是分析AsyncTask的源代码以及使用时候的一些注意事项,如果你还不熟悉AsyncTask,请先阅读android之AsyncTask来了解其基本用法。

这里先给出AsyncTask的一个例子:

[java] view plain copy
  1. privateclassDownloadFilesTaskextendsAsyncTask<URL,Integer,Long>{
  2. protectedLongdoInBackground(URL...urls){
  3. intcount=urls.length;
  4. longtotalSize=0;
  5. for(inti=0;i<count;i++){
  6. totalSize+=Downloader.downloadFile(urls[i]);
  7. publishProgress((int)((i/(float)count)*100));
  8. //Escapeearlyifcancel()iscalled
  9. if(isCancelled())break;
  10. }
  11. returntotalSize;
  12. }
  13. protectedvoidonProgressUpdate(Integer...progress){
  14. setProgressPercent(progress[0]);
  15. }
  16. protectedvoidonPostExecute(Longresult){
  17. showDialog("Downloaded"+result+"bytes");
  18. }
  19. }

使用AsyncTask的规则

  • AsyncTask的类必须在UI线程加载(从4.1开始系统会帮我们自动完成)
  • AsyncTask对象必须在UI线程创建
  • execute方法必须在UI线程调用
  • 不要在你的程序中去直接调用onPreExecute(), onPostExecute, doInBackground, onProgressUpdate方法
  • 一个AsyncTask对象只能执行一次,即只能调用一次execute方法,否则会报运行时异常
  • AsyncTask不是被设计为处理耗时操作的,耗时上限为几秒钟,如果要做长耗时操作,强烈建议你使用Executor,ThreadPoolExecutor以及FutureTask
  • 在1.6之前,AsyncTask是串行执行任务的,1.6的时候AsyncTask开始采用线程池里处理并行任务,但是从3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask又采用一个线程来串行执行任务

AsyncTask到底是串行还是并行?

给大家做一下实验,请看如下实验代码:代码很简单,就是点击按钮的时候同时执行5个AsyncTask,每个AsyncTask休眠3s,同时把每个AsyncTask执行结束的时间打印出来,这样我们就能观察出到底是串行执行还是并行执行。

[java] view plain copy
  1. @Override
  2. publicvoidonClick(Viewv){
  3. if(v==mButton){
  4. newMyAsyncTask("AsyncTask#1").execute("");
  5. newMyAsyncTask("AsyncTask#2").execute("");
  6. newMyAsyncTask("AsyncTask#3").execute("");
  7. newMyAsyncTask("AsyncTask#4").execute("");
  8. newMyAsyncTask("AsyncTask#5").execute("");
  9. }
  10. }
  11. privatestaticclassMyAsyncTaskextendsAsyncTask<String,Integer,String>{
  12. privateStringmName="AsyncTask";
  13. publicMyAsyncTask(Stringname){
  14. super();
  15. mName=name;
  16. }
  17. @Override
  18. protectedStringdoInBackground(String...params){
  19. try{
  20. Thread.sleep(3000);
  21. }catch(InterruptedExceptione){
  22. e.printStackTrace();
  23. }
  24. returnmName;
  25. }
  26. @Override
  27. protectedvoidonPostExecute(Stringresult){
  28. super.onPostExecute(result);
  29. SimpleDateFormatdf=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");
  30. Log.e(TAG,result+"executefinishat"+df.format(newDate()));
  31. }
  32. }
我找了2个手机,系统分别是4.1.1和2.3.3,按照我前面的描述,AsyncTask在4.1.1应该是串行的,在2.3.3应该是并行的,到底是不是这样呢?请看Log

Android 4.1.1上执行:从下面Log可以看出,5个AsyncTask共耗时15s且时间间隔为3s,很显然是串行执行的


Android 2.3.3上执行:从下面Log可以看出,5个AsyncTask的结束时间是一样的,很显然是并行执行


结论:从上面的两个Log可以看出,我前面的描述是完全正确的。下面请看源码,让我们去了解下其中的原理。

源码分析

[java] view plain copy
  1. /*
  2. *Copyright(C)2008TheAndroidOpenSourceProject
  3. *
  4. *LicensedundertheApacheLicense,Version2.0(the"License");
  5. *youmaynotusethisfileexceptincompliancewiththeLicense.
  6. *YoumayobtainacopyoftheLicenseat
  7. *
  8. *http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. *Unlessrequiredbyapplicablelaworagreedtoinwriting,software
  11. *distributedundertheLicenseisdistributedonan"ASIS"BASIS,
  12. *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
  13. *SeetheLicenseforthespecificlanguagegoverningpermissionsand
  14. *limitationsundertheLicense.
  15. */
  16. packageandroid.os;
  17. importjava.util.ArrayDeque;
  18. importjava.util.concurrent.BlockingQueue;
  19. importjava.util.concurrent.Callable;
  20. importjava.util.concurrent.CancellationException;
  21. importjava.util.concurrent.Executor;
  22. importjava.util.concurrent.ExecutionException;
  23. importjava.util.concurrent.FutureTask;
  24. importjava.util.concurrent.LinkedBlockingQueue;
  25. importjava.util.concurrent.ThreadFactory;
  26. importjava.util.concurrent.ThreadPoolExecutor;
  27. importjava.util.concurrent.TimeUnit;
  28. importjava.util.concurrent.TimeoutException;
  29. importjava.util.concurrent.atomic.AtomicBoolean;
  30. importjava.util.concurrent.atomic.AtomicInteger;
  31. publicabstractclassAsyncTask<Params,Progress,Result>{
  32. privatestaticfinalStringLOG_TAG="AsyncTask";
  33. //获取当前的cpu核心数
  34. privatestaticfinalintCPU_COUNT=Runtime.getRuntime().availableProcessors();
  35. //线程池核心容量
  36. privatestaticfinalintCORE_POOL_SIZE=CPU_COUNT+1;
  37. //线程池最大容量
  38. privatestaticfinalintMAXIMUM_POOL_SIZE=CPU_COUNT*2+1;
  39. //过剩的空闲线程的存活时间
  40. privatestaticfinalintKEEP_ALIVE=1;
  41. //ThreadFactory线程工厂,通过工厂方法newThread来获取新线程
  42. privatestaticfinalThreadFactorysThreadFactory=newThreadFactory(){
  43. //原子整数,可以在超高并发下正常工作
  44. privatefinalAtomicIntegermCount=newAtomicInteger(1);
  45. publicThreadnewThread(Runnabler){
  46. returnnewThread(r,"AsyncTask#"+mCount.getAndIncrement());
  47. }
  48. };
  49. //静态阻塞式队列,用来存放待执行的任务,初始容量:128个
  50. privatestaticfinalBlockingQueue<Runnable>sPoolWorkQueue=
  51. newLinkedBlockingQueue<Runnable>(128);
  52. /**
  53. *静态并发线程池,可以用来并行执行任务,尽管从3.0开始,AsyncTask默认是串行执行任务
  54. *但是我们仍然能构造出并行的AsyncTask
  55. */
  56. publicstaticfinalExecutorTHREAD_POOL_EXECUTOR
  57. =newThreadPoolExecutor(CORE_POOL_SIZE,MAXIMUM_POOL_SIZE,KEEP_ALIVE,
  58. TimeUnit.SECONDS,sPoolWorkQueue,sThreadFactory);
  59. /**
  60. *静态串行任务执行器,其内部实现了串行控制,
  61. *循环的取出一个个任务交给上述的并发线程池去执行
  62. */
  63. publicstaticfinalExecutorSERIAL_EXECUTOR=newSerialExecutor();
  64. //消息类型:发送结果
  65. privatestaticfinalintMESSAGE_POST_RESULT=0x1;
  66. //消息类型:更新进度
  67. privatestaticfinalintMESSAGE_POST_PROGRESS=0x2;
  68. /**静态Handler,用来发送上述两种通知,采用UI线程的Looper来处理消息
  69. *这就是为什么AsyncTask必须在UI线程调用,因为子线程
  70. *默认没有Looper无法创建下面的Handler,程序会直接Crash
  71. */
  72. privatestaticfinalInternalHandlersHandler=newInternalHandler();
  73. //默认任务执行器,被赋值为串行任务执行器,就是它,AsyncTask变成串行的了
  74. privatestaticvolatileExecutorsDefaultExecutor=SERIAL_EXECUTOR;
  75. //如下两个变量我们先不要深究,不影响我们对整体逻辑的理解
  76. privatefinalWorkerRunnable<Params,Result>mWorker;
  77. privatefinalFutureTask<Result>mFuture;
  78. //任务的状态默认为挂起,即等待执行,其类型标识为易变的(volatile)
  79. privatevolatileStatusmStatus=Status.PENDING;
  80. //原子布尔型,支持高并发访问,标识任务是否被取消
  81. privatefinalAtomicBooleanmCancelled=newAtomicBoolean();
  82. //原子布尔型,支持高并发访问,标识任务是否被执行过
  83. privatefinalAtomicBooleanmTaskInvoked=newAtomicBoolean();
  84. /*串行执行器的实现,我们要好好看看,它是怎么把并行转为串行的
  85. *目前我们需要知道,asyncTask.execute(Params...)实际上会调用
  86. *SerialExecutor的execute方法,这一点后面再说明。也就是说:当你的asyncTask执行的时候,
  87. *首先你的task会被加入到任务队列,然后排队,一个个执行
  88. */
  89. privatestaticclassSerialExecutorimplementsExecutor{
  90. //线性双向队列,用来存储所有的AsyncTask任务
  91. finalArrayDeque<Runnable>mTasks=newArrayDeque<Runnable>();
  92. //当前正在执行的AsyncTask任务
  93. RunnablemActive;
  94. publicsynchronizedvoidexecute(finalRunnabler){
  95. //将新的AsyncTask任务加入到双向队列中
  96. mTasks.offer(newRunnable(){
  97. publicvoidrun(){
  98. try{
  99. //执行AsyncTask任务
  100. r.run();
  101. }finally{
  102. //当前AsyncTask任务执行完毕后,进行下一轮执行,如果还有未执行任务的话
  103. //这一点很明显体现了AsyncTask是串行执行任务的,总是一个任务执行完毕才会执行下一个任务
  104. scheduleNext();
  105. }
  106. }
  107. });
  108. //如果当前没有任务在执行,直接进入执行逻辑
  109. if(mActive==null){
  110. scheduleNext();
  111. }
  112. }
  113. protectedsynchronizedvoidscheduleNext(){
  114. //从任务队列中取出队列头部的任务,如果有就交给并发线程池去执行
  115. if((mActive=mTasks.poll())!=null){
  116. THREAD_POOL_EXECUTOR.execute(mActive);
  117. }
  118. }
  119. }
  120. /**
  121. *任务的三种状态
  122. */
  123. publicenumStatus{
  124. /**
  125. *任务等待执行
  126. */
  127. PENDING,
  128. /**
  129. *任务正在执行
  130. */
  131. RUNNING,
  132. /**
  133. *任务已经执行结束
  134. */
  135. FINISHED,
  136. }
  137. /**隐藏API:在UI线程中调用,用来初始化Handler*/
  138. publicstaticvoidinit(){
  139. sHandler.getLooper();
  140. }
  141. /**隐藏API:为AsyncTask设置默认执行器*/
  142. publicstaticvoidsetDefaultExecutor(Executorexec){
  143. sDefaultExecutor=exec;
  144. }
  145. /**
  146. *Createsanewasynchronoustask.ThisconstructormustbeinvokedontheUIthread.
  147. */
  148. publicAsyncTask(){
  149. mWorker=newWorkerRunnable<Params,Result>(){
  150. publicResultcall()throwsException{
  151. mTaskInvoked.set(true);
  152. Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
  153. //noinspectionunchecked
  154. returnpostResult(doInBackground(mParams));
  155. }
  156. };
  157. mFuture=newFutureTask<Result>(mWorker){
  158. @Override
  159. protectedvoiddone(){
  160. try{
  161. postResultIfNotInvoked(get());
  162. }catch(InterruptedExceptione){
  163. android.util.Log.w(LOG_TAG,e);
  164. }catch(ExecutionExceptione){
  165. thrownewRuntimeException("AnerroroccuredwhileexecutingdoInBackground()",
  166. e.getCause());
  167. }catch(CancellationExceptione){
  168. postResultIfNotInvoked(null);
  169. }
  170. }
  171. };
  172. }
  173. privatevoidpostResultIfNotInvoked(Resultresult){
  174. finalbooleanwasTaskInvoked=mTaskInvoked.get();
  175. if(!wasTaskInvoked){
  176. postResult(result);
  177. }
  178. }
  179. //doInBackground执行完毕,发送消息
  180. privateResultpostResult(Resultresult){
  181. @SuppressWarnings("unchecked")
  182. Messagemessage=sHandler.obtainMessage(MESSAGE_POST_RESULT,
  183. newAsyncTaskResult<Result>(this,result));
  184. message.sendToTarget();
  185. returnresult;
  186. }
  187. /**
  188. *返回任务的状态
  189. */
  190. publicfinalStatusgetStatus(){
  191. returnmStatus;
  192. }
  193. /**
  194. *这个方法是我们必须要重写的,用来做后台计算
  195. *所在线程:后台线程
  196. */
  197. protectedabstractResultdoInBackground(Params...params);
  198. /**
  199. *在doInBackground之前调用,用来做初始化工作
  200. *所在线程:UI线程
  201. */
  202. protectedvoidonPreExecute(){
  203. }
  204. /**
  205. *在doInBackground之后调用,用来接受后台计算结果更新UI
  206. *所在线程:UI线程
  207. */
  208. protectedvoidonPostExecute(Resultresult){
  209. }
  210. /**
  211. *RunsontheUIthreadafter{@link#publishProgress}isinvoked.
  212. /**
  213. *在publishProgress之后调用,用来更新计算进度
  214. *所在线程:UI线程
  215. */
  216. protectedvoidonProgressUpdate(Progress...values){
  217. }
  218. /**
  219. *cancel被调用并且doInBackground执行结束,会调用onCancelled,表示任务被取消
  220. *这个时候onPostExecute不会再被调用,二者是互斥的,分别表示任务取消和任务执行完成
  221. *所在线程:UI线程
  222. */
  223. @SuppressWarnings({"UnusedParameters"})
  224. protectedvoidonCancelled(Resultresult){
  225. onCancelled();
  226. }
  227. protectedvoidonCancelled(){
  228. }
  229. publicfinalbooleanisCancelled(){
  230. returnmCancelled.get();
  231. }
  232. publicfinalbooleancancel(booleanmayInterruptIfRunning){
  233. mCancelled.set(true);
  234. returnmFuture.cancel(mayInterruptIfRunning);
  235. }
  236. publicfinalResultget()throwsInterruptedException,ExecutionException{
  237. returnmFuture.get();
  238. }
  239. publicfinalResultget(longtimeout,TimeUnitunit)throwsInterruptedException,
  240. ExecutionException,TimeoutException{
  241. returnmFuture.get(timeout,unit);
  242. }
  243. /**
  244. *这个方法如何执行和系统版本有关,在AsyncTask的使用规则里已经说明,如果你真的想使用并行AsyncTask,
  245. *也是可以的,只要稍作修改
  246. *必须在UI线程调用此方法
  247. */
  248. publicfinalAsyncTask<Params,Progress,Result>execute(Params...params){
  249. //串行执行
  250. returnexecuteOnExecutor(sDefaultExecutor,params);
  251. //如果我们想并行执行,这样改就行了,当然这个方法我们没法改
  252. //returnexecuteOnExecutor(THREAD_POOL_EXECUTOR,params);
  253. }
  254. /**
  255. *通过这个方法我们可以自定义AsyncTask的执行方式,串行or并行,甚至可以采用自己的Executor
  256. *为了实现并行,我们可以在外部这么用AsyncTask:
  257. *asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,Params...params);
  258. *必须在UI线程调用此方法
  259. */
  260. publicfinalAsyncTask<Params,Progress,Result>executeOnExecutor(Executorexec,
  261. Params...params){
  262. if(mStatus!=Status.PENDING){
  263. switch(mStatus){
  264. caseRUNNING:
  265. thrownewIllegalStateException("Cannotexecutetask:"
  266. +"thetaskisalreadyrunning.");
  267. caseFINISHED:
  268. thrownewIllegalStateException("Cannotexecutetask:"
  269. +"thetaskhasalreadybeenexecuted"
  270. +"(ataskcanbeexecutedonlyonce)");
  271. }
  272. }
  273. mStatus=Status.RUNNING;
  274. //这里#onPreExecute会最先执行
  275. onPreExecute();
  276. mWorker.mParams=params;
  277. //然后后台计算#doInBackground才真正开始
  278. exec.execute(mFuture);
  279. //接着会有#onProgressUpdate被调用,最后是#onPostExecute
  280. returnthis;
  281. }
  282. /**
  283. *这是AsyncTask提供的一个静态方法,方便我们直接执行一个runnable
  284. */
  285. publicstaticvoidexecute(Runnablerunnable){
  286. sDefaultExecutor.execute(runnable);
  287. }
  288. /**
  289. *打印后台计算进度,onProgressUpdate会被调用
  290. */
  291. protectedfinalvoidpublishProgress(Progress...values){
  292. if(!isCancelled()){
  293. sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
  294. newAsyncTaskResult<Progress>(this,values)).sendToTarget();
  295. }
  296. }
  297. //任务结束的时候会进行判断,如果任务没有被取消,则onPostExecute会被调用
  298. privatevoidfinish(Resultresult){
  299. if(isCancelled()){
  300. onCancelled(result);
  301. }else{
  302. onPostExecute(result);
  303. }
  304. mStatus=Status.FINISHED;
  305. }
  306. //AsyncTask内部Handler,用来发送后台计算进度更新消息和计算完成消息
  307. privatestaticclassInternalHandlerextendsHandler{
  308. @SuppressWarnings({"unchecked","RawUseOfParameterizedType"})
  309. @Override
  310. publicvoidhandleMessage(Messagemsg){
  311. AsyncTaskResultresult=(AsyncTaskResult)msg.obj;
  312. switch(msg.what){
  313. caseMESSAGE_POST_RESULT:
  314. //Thereisonlyoneresult
  315. result.mTask.finish(result.mData[0]);
  316. break;
  317. caseMESSAGE_POST_PROGRESS:
  318. result.mTask.onProgressUpdate(result.mData);
  319. break;
  320. }
  321. }
  322. }
  323. privatestaticabstractclassWorkerRunnable<Params,Result>implementsCallable<Result>{
  324. Params[]mParams;
  325. }
  326. @SuppressWarnings({"RawUseOfParameterizedType"})
  327. privatestaticclassAsyncTaskResult<Data>{
  328. finalAsyncTaskmTask;
  329. finalData[]mData;
  330. AsyncTaskResult(AsyncTasktask,Data...data){
  331. mTask=task;
  332. mData=data;
  333. }
  334. }
  335. }

让你的AsyncTask在3.0以上的系统中并行起来

通过上面的源码分析,我已经给出了在3.0以上系统中让AsyncTask并行执行的方法,现在,让我们来试一试,代码还是之前采用的测试代码,我们要稍作修改,调用AsyncTask的executeOnExecutor方法而不是execute,请看:

[java] view plain copy
  1. @TargetApi(Build.VERSION_CODES.HONEYCOMB)
  2. @Override
  3. publicvoidonClick(Viewv){
  4. if(v==mButton){
  5. newMyAsyncTask("AsyncTask#1").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"");
  6. newMyAsyncTask("AsyncTask#2").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"");
  7. newMyAsyncTask("AsyncTask#3").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"");
  8. newMyAsyncTask("AsyncTask#4").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"");
  9. newMyAsyncTask("AsyncTask#5").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"");
  10. }
  11. }
  12. privatestaticclassMyAsyncTaskextendsAsyncTask<String,Integer,String>{
  13. privateStringmName="AsyncTask";
  14. publicMyAsyncTask(Stringname){
  15. super();
  16. mName=name;
  17. }
  18. @Override
  19. protectedStringdoInBackground(String...params){
  20. try{
  21. Thread.sleep(3000);
  22. }catch(InterruptedExceptione){
  23. e.printStackTrace();
  24. }
  25. returnmName;
  26. }
  27. @Override
  28. protectedvoidonPostExecute(Stringresult){
  29. super.onPostExecute(result);
  30. SimpleDateFormatdf=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");
  31. Log.e(TAG,result+"executefinishat"+df.format(newDate()));
  32. }
  33. }
下面是系统为4.1.1手机打印出的Log:很显然,我们的目的达到了,成功的让AsyncTask在4.1.1的手机上并行起来了,很高兴吧!希望这篇文章对你有用。






更多相关文章

  1. SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
  2. [置顶] Android硬件加速
  3. android连接真机 调试未测试
  4. Android系统稳定性-ANR
  5. Android的Activity什么时候会调用onCreate()而不调用onStart()?
  6. Handler消息机制 源码解读
  7. AsyncTask工作原理分析
  8. android studio 导入Google源码
  9. Android的DDMS中的Threads的各个字段的含义

随机推荐

  1. Android(安卓)intent.Action 参数值及对
  2. 关于Android(安卓)Studio 查看源码 throw
  3. android第一天:搭建基础环境
  4. Android(安卓)studio里Toast,menu的用法
  5. android4.0去掉锁屏和休眠 Power键按钮
  6. android的日期格式化 android.text.forma
  7. Android::整理基础之—— startActivityFor
  8. Android关于获取时间的记录(小结)
  9. Android源码中的单例模式
  10. android传感器sensor