【android】AsyncTask完全剖析(一)
转载请注明出处: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
- privateclassDownloadFilesTaskextendsAsyncTask<URL,Integer,Long>{
- protectedLongdoInBackground(URL...urls){
- intcount=urls.length;
- longtotalSize=0;
- for(inti=0;i<count;i++){
- totalSize+=Downloader.downloadFile(urls[i]);
- publishProgress((int)((i/(float)count)*100));
- //Escapeearlyifcancel()iscalled
- if(isCancelled())break;
- }
- returntotalSize;
- }
- protectedvoidonProgressUpdate(Integer...progress){
- setProgressPercent(progress[0]);
- }
- protectedvoidonPostExecute(Longresult){
- showDialog("Downloaded"+result+"bytes");
- }
- }
使用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
- @Override
- publicvoidonClick(Viewv){
- if(v==mButton){
- newMyAsyncTask("AsyncTask#1").execute("");
- newMyAsyncTask("AsyncTask#2").execute("");
- newMyAsyncTask("AsyncTask#3").execute("");
- newMyAsyncTask("AsyncTask#4").execute("");
- newMyAsyncTask("AsyncTask#5").execute("");
- }
- }
- privatestaticclassMyAsyncTaskextendsAsyncTask<String,Integer,String>{
- privateStringmName="AsyncTask";
- publicMyAsyncTask(Stringname){
- super();
- mName=name;
- }
- @Override
- protectedStringdoInBackground(String...params){
- try{
- Thread.sleep(3000);
- }catch(InterruptedExceptione){
- e.printStackTrace();
- }
- returnmName;
- }
- @Override
- protectedvoidonPostExecute(Stringresult){
- super.onPostExecute(result);
- SimpleDateFormatdf=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");
- Log.e(TAG,result+"executefinishat"+df.format(newDate()));
- }
- }
Android 4.1.1上执行:从下面Log可以看出,5个AsyncTask共耗时15s且时间间隔为3s,很显然是串行执行的
Android 2.3.3上执行:从下面Log可以看出,5个AsyncTask的结束时间是一样的,很显然是并行执行
结论:从上面的两个Log可以看出,我前面的描述是完全正确的。下面请看源码,让我们去了解下其中的原理。
源码分析
[java] view plain copy
- /*
- *Copyright(C)2008TheAndroidOpenSourceProject
- *
- *LicensedundertheApacheLicense,Version2.0(the"License");
- *youmaynotusethisfileexceptincompliancewiththeLicense.
- *YoumayobtainacopyoftheLicenseat
- *
- *http://www.apache.org/licenses/LICENSE-2.0
- *
- *Unlessrequiredbyapplicablelaworagreedtoinwriting,software
- *distributedundertheLicenseisdistributedonan"ASIS"BASIS,
- *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
- *SeetheLicenseforthespecificlanguagegoverningpermissionsand
- *limitationsundertheLicense.
- */
- packageandroid.os;
- importjava.util.ArrayDeque;
- importjava.util.concurrent.BlockingQueue;
- importjava.util.concurrent.Callable;
- importjava.util.concurrent.CancellationException;
- importjava.util.concurrent.Executor;
- importjava.util.concurrent.ExecutionException;
- importjava.util.concurrent.FutureTask;
- importjava.util.concurrent.LinkedBlockingQueue;
- importjava.util.concurrent.ThreadFactory;
- importjava.util.concurrent.ThreadPoolExecutor;
- importjava.util.concurrent.TimeUnit;
- importjava.util.concurrent.TimeoutException;
- importjava.util.concurrent.atomic.AtomicBoolean;
- importjava.util.concurrent.atomic.AtomicInteger;
- publicabstractclassAsyncTask<Params,Progress,Result>{
- privatestaticfinalStringLOG_TAG="AsyncTask";
- //获取当前的cpu核心数
- privatestaticfinalintCPU_COUNT=Runtime.getRuntime().availableProcessors();
- //线程池核心容量
- privatestaticfinalintCORE_POOL_SIZE=CPU_COUNT+1;
- //线程池最大容量
- privatestaticfinalintMAXIMUM_POOL_SIZE=CPU_COUNT*2+1;
- //过剩的空闲线程的存活时间
- privatestaticfinalintKEEP_ALIVE=1;
- //ThreadFactory线程工厂,通过工厂方法newThread来获取新线程
- privatestaticfinalThreadFactorysThreadFactory=newThreadFactory(){
- //原子整数,可以在超高并发下正常工作
- privatefinalAtomicIntegermCount=newAtomicInteger(1);
- publicThreadnewThread(Runnabler){
- returnnewThread(r,"AsyncTask#"+mCount.getAndIncrement());
- }
- };
- //静态阻塞式队列,用来存放待执行的任务,初始容量:128个
- privatestaticfinalBlockingQueue<Runnable>sPoolWorkQueue=
- newLinkedBlockingQueue<Runnable>(128);
- /**
- *静态并发线程池,可以用来并行执行任务,尽管从3.0开始,AsyncTask默认是串行执行任务
- *但是我们仍然能构造出并行的AsyncTask
- */
- publicstaticfinalExecutorTHREAD_POOL_EXECUTOR
- =newThreadPoolExecutor(CORE_POOL_SIZE,MAXIMUM_POOL_SIZE,KEEP_ALIVE,
- TimeUnit.SECONDS,sPoolWorkQueue,sThreadFactory);
- /**
- *静态串行任务执行器,其内部实现了串行控制,
- *循环的取出一个个任务交给上述的并发线程池去执行
- */
- publicstaticfinalExecutorSERIAL_EXECUTOR=newSerialExecutor();
- //消息类型:发送结果
- privatestaticfinalintMESSAGE_POST_RESULT=0x1;
- //消息类型:更新进度
- privatestaticfinalintMESSAGE_POST_PROGRESS=0x2;
- /**静态Handler,用来发送上述两种通知,采用UI线程的Looper来处理消息
- *这就是为什么AsyncTask必须在UI线程调用,因为子线程
- *默认没有Looper无法创建下面的Handler,程序会直接Crash
- */
- privatestaticfinalInternalHandlersHandler=newInternalHandler();
- //默认任务执行器,被赋值为串行任务执行器,就是它,AsyncTask变成串行的了
- privatestaticvolatileExecutorsDefaultExecutor=SERIAL_EXECUTOR;
- //如下两个变量我们先不要深究,不影响我们对整体逻辑的理解
- privatefinalWorkerRunnable<Params,Result>mWorker;
- privatefinalFutureTask<Result>mFuture;
- //任务的状态默认为挂起,即等待执行,其类型标识为易变的(volatile)
- privatevolatileStatusmStatus=Status.PENDING;
- //原子布尔型,支持高并发访问,标识任务是否被取消
- privatefinalAtomicBooleanmCancelled=newAtomicBoolean();
- //原子布尔型,支持高并发访问,标识任务是否被执行过
- privatefinalAtomicBooleanmTaskInvoked=newAtomicBoolean();
- /*串行执行器的实现,我们要好好看看,它是怎么把并行转为串行的
- *目前我们需要知道,asyncTask.execute(Params...)实际上会调用
- *SerialExecutor的execute方法,这一点后面再说明。也就是说:当你的asyncTask执行的时候,
- *首先你的task会被加入到任务队列,然后排队,一个个执行
- */
- privatestaticclassSerialExecutorimplementsExecutor{
- //线性双向队列,用来存储所有的AsyncTask任务
- finalArrayDeque<Runnable>mTasks=newArrayDeque<Runnable>();
- //当前正在执行的AsyncTask任务
- RunnablemActive;
- publicsynchronizedvoidexecute(finalRunnabler){
- //将新的AsyncTask任务加入到双向队列中
- mTasks.offer(newRunnable(){
- publicvoidrun(){
- try{
- //执行AsyncTask任务
- r.run();
- }finally{
- //当前AsyncTask任务执行完毕后,进行下一轮执行,如果还有未执行任务的话
- //这一点很明显体现了AsyncTask是串行执行任务的,总是一个任务执行完毕才会执行下一个任务
- scheduleNext();
- }
- }
- });
- //如果当前没有任务在执行,直接进入执行逻辑
- if(mActive==null){
- scheduleNext();
- }
- }
- protectedsynchronizedvoidscheduleNext(){
- //从任务队列中取出队列头部的任务,如果有就交给并发线程池去执行
- if((mActive=mTasks.poll())!=null){
- THREAD_POOL_EXECUTOR.execute(mActive);
- }
- }
- }
- /**
- *任务的三种状态
- */
- publicenumStatus{
- /**
- *任务等待执行
- */
- PENDING,
- /**
- *任务正在执行
- */
- RUNNING,
- /**
- *任务已经执行结束
- */
- FINISHED,
- }
- /**隐藏API:在UI线程中调用,用来初始化Handler*/
- publicstaticvoidinit(){
- sHandler.getLooper();
- }
- /**隐藏API:为AsyncTask设置默认执行器*/
- publicstaticvoidsetDefaultExecutor(Executorexec){
- sDefaultExecutor=exec;
- }
- /**
- *Createsanewasynchronoustask.ThisconstructormustbeinvokedontheUIthread.
- */
- publicAsyncTask(){
- mWorker=newWorkerRunnable<Params,Result>(){
- publicResultcall()throwsException{
- mTaskInvoked.set(true);
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- //noinspectionunchecked
- returnpostResult(doInBackground(mParams));
- }
- };
- mFuture=newFutureTask<Result>(mWorker){
- @Override
- protectedvoiddone(){
- try{
- postResultIfNotInvoked(get());
- }catch(InterruptedExceptione){
- android.util.Log.w(LOG_TAG,e);
- }catch(ExecutionExceptione){
- thrownewRuntimeException("AnerroroccuredwhileexecutingdoInBackground()",
- e.getCause());
- }catch(CancellationExceptione){
- postResultIfNotInvoked(null);
- }
- }
- };
- }
- privatevoidpostResultIfNotInvoked(Resultresult){
- finalbooleanwasTaskInvoked=mTaskInvoked.get();
- if(!wasTaskInvoked){
- postResult(result);
- }
- }
- //doInBackground执行完毕,发送消息
- privateResultpostResult(Resultresult){
- @SuppressWarnings("unchecked")
- Messagemessage=sHandler.obtainMessage(MESSAGE_POST_RESULT,
- newAsyncTaskResult<Result>(this,result));
- message.sendToTarget();
- returnresult;
- }
- /**
- *返回任务的状态
- */
- publicfinalStatusgetStatus(){
- returnmStatus;
- }
- /**
- *这个方法是我们必须要重写的,用来做后台计算
- *所在线程:后台线程
- */
- protectedabstractResultdoInBackground(Params...params);
- /**
- *在doInBackground之前调用,用来做初始化工作
- *所在线程:UI线程
- */
- protectedvoidonPreExecute(){
- }
- /**
- *在doInBackground之后调用,用来接受后台计算结果更新UI
- *所在线程:UI线程
- */
- protectedvoidonPostExecute(Resultresult){
- }
- /**
- *RunsontheUIthreadafter{@link#publishProgress}isinvoked.
- /**
- *在publishProgress之后调用,用来更新计算进度
- *所在线程:UI线程
- */
- protectedvoidonProgressUpdate(Progress...values){
- }
- /**
- *cancel被调用并且doInBackground执行结束,会调用onCancelled,表示任务被取消
- *这个时候onPostExecute不会再被调用,二者是互斥的,分别表示任务取消和任务执行完成
- *所在线程:UI线程
- */
- @SuppressWarnings({"UnusedParameters"})
- protectedvoidonCancelled(Resultresult){
- onCancelled();
- }
- protectedvoidonCancelled(){
- }
- publicfinalbooleanisCancelled(){
- returnmCancelled.get();
- }
- publicfinalbooleancancel(booleanmayInterruptIfRunning){
- mCancelled.set(true);
- returnmFuture.cancel(mayInterruptIfRunning);
- }
- publicfinalResultget()throwsInterruptedException,ExecutionException{
- returnmFuture.get();
- }
- publicfinalResultget(longtimeout,TimeUnitunit)throwsInterruptedException,
- ExecutionException,TimeoutException{
- returnmFuture.get(timeout,unit);
- }
- /**
- *这个方法如何执行和系统版本有关,在AsyncTask的使用规则里已经说明,如果你真的想使用并行AsyncTask,
- *也是可以的,只要稍作修改
- *必须在UI线程调用此方法
- */
- publicfinalAsyncTask<Params,Progress,Result>execute(Params...params){
- //串行执行
- returnexecuteOnExecutor(sDefaultExecutor,params);
- //如果我们想并行执行,这样改就行了,当然这个方法我们没法改
- //returnexecuteOnExecutor(THREAD_POOL_EXECUTOR,params);
- }
- /**
- *通过这个方法我们可以自定义AsyncTask的执行方式,串行or并行,甚至可以采用自己的Executor
- *为了实现并行,我们可以在外部这么用AsyncTask:
- *asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,Params...params);
- *必须在UI线程调用此方法
- */
- publicfinalAsyncTask<Params,Progress,Result>executeOnExecutor(Executorexec,
- Params...params){
- if(mStatus!=Status.PENDING){
- switch(mStatus){
- caseRUNNING:
- thrownewIllegalStateException("Cannotexecutetask:"
- +"thetaskisalreadyrunning.");
- caseFINISHED:
- thrownewIllegalStateException("Cannotexecutetask:"
- +"thetaskhasalreadybeenexecuted"
- +"(ataskcanbeexecutedonlyonce)");
- }
- }
- mStatus=Status.RUNNING;
- //这里#onPreExecute会最先执行
- onPreExecute();
- mWorker.mParams=params;
- //然后后台计算#doInBackground才真正开始
- exec.execute(mFuture);
- //接着会有#onProgressUpdate被调用,最后是#onPostExecute
- returnthis;
- }
- /**
- *这是AsyncTask提供的一个静态方法,方便我们直接执行一个runnable
- */
- publicstaticvoidexecute(Runnablerunnable){
- sDefaultExecutor.execute(runnable);
- }
- /**
- *打印后台计算进度,onProgressUpdate会被调用
- */
- protectedfinalvoidpublishProgress(Progress...values){
- if(!isCancelled()){
- sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
- newAsyncTaskResult<Progress>(this,values)).sendToTarget();
- }
- }
- //任务结束的时候会进行判断,如果任务没有被取消,则onPostExecute会被调用
- privatevoidfinish(Resultresult){
- if(isCancelled()){
- onCancelled(result);
- }else{
- onPostExecute(result);
- }
- mStatus=Status.FINISHED;
- }
- //AsyncTask内部Handler,用来发送后台计算进度更新消息和计算完成消息
- privatestaticclassInternalHandlerextendsHandler{
- @SuppressWarnings({"unchecked","RawUseOfParameterizedType"})
- @Override
- publicvoidhandleMessage(Messagemsg){
- AsyncTaskResultresult=(AsyncTaskResult)msg.obj;
- switch(msg.what){
- caseMESSAGE_POST_RESULT:
- //Thereisonlyoneresult
- result.mTask.finish(result.mData[0]);
- break;
- caseMESSAGE_POST_PROGRESS:
- result.mTask.onProgressUpdate(result.mData);
- break;
- }
- }
- }
- privatestaticabstractclassWorkerRunnable<Params,Result>implementsCallable<Result>{
- Params[]mParams;
- }
- @SuppressWarnings({"RawUseOfParameterizedType"})
- privatestaticclassAsyncTaskResult<Data>{
- finalAsyncTaskmTask;
- finalData[]mData;
- AsyncTaskResult(AsyncTasktask,Data...data){
- mTask=task;
- mData=data;
- }
- }
- }
让你的AsyncTask在3.0以上的系统中并行起来
通过上面的源码分析,我已经给出了在3.0以上系统中让AsyncTask并行执行的方法,现在,让我们来试一试,代码还是之前采用的测试代码,我们要稍作修改,调用AsyncTask的executeOnExecutor方法而不是execute,请看:
[java] view plain copy
- @TargetApi(Build.VERSION_CODES.HONEYCOMB)
- @Override
- publicvoidonClick(Viewv){
- if(v==mButton){
- newMyAsyncTask("AsyncTask#1").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"");
- newMyAsyncTask("AsyncTask#2").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"");
- newMyAsyncTask("AsyncTask#3").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"");
- newMyAsyncTask("AsyncTask#4").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"");
- newMyAsyncTask("AsyncTask#5").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"");
- }
- }
- privatestaticclassMyAsyncTaskextendsAsyncTask<String,Integer,String>{
- privateStringmName="AsyncTask";
- publicMyAsyncTask(Stringname){
- super();
- mName=name;
- }
- @Override
- protectedStringdoInBackground(String...params){
- try{
- Thread.sleep(3000);
- }catch(InterruptedExceptione){
- e.printStackTrace();
- }
- returnmName;
- }
- @Override
- protectedvoidonPostExecute(Stringresult){
- super.onPostExecute(result);
- SimpleDateFormatdf=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");
- Log.e(TAG,result+"executefinishat"+df.format(newDate()));
- }
- }
更多相关文章
- SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
- [置顶] Android硬件加速
- android连接真机 调试未测试
- Android系统稳定性-ANR
- Android的Activity什么时候会调用onCreate()而不调用onStart()?
- Handler消息机制 源码解读
- AsyncTask工作原理分析
- android studio 导入Google源码
- Android的DDMS中的Threads的各个字段的含义