概述 
AsyncTask是一个抽象类,它是Android封装的一个轻量级异步操作的类。它可以在线程池中执行后台任务,然后把执行的进度和最终的结果传递到主线程,并在主线程中更新UI。
 
AsyncTask简介 AsyncTask的泛型参数 AsyncTask的类声明:
1 public  abstract  class  AsyncTask <Params , Progress , Result >
泛型参数说明:
Params :执行异步任务时传入的参数类型。
Progress :在后台执行时,发布的进度单位类型。
Result :异步任务执行完成后,返回的结果类型。
AsyncTask的核心方法 onPreExecute() 
该方法会在后台任务开始执行前调用,并在主线程执行。用于进行一些界面上的初始化操作,比如显示一个进度条对话框等。
 
doInBackground(Params…) 
这个方法在子线程中运行,应该在这里处理所有的耗时任务。
任务执行结束,可以通过return语句来返回任务执行的结果。这个方法不能执行UI操作,如果需要进行UI更新操作,如更新任务进度,可以调用publishProgress(Progress…)来完成。
 
onProgressUpdate(Progress…) 
当在后台任务中调用publishProgress(Progress…)后,这个方法就会马上被调用,方法中携带的参数是后台任务传过来的,该方法在主线程运行,所以可以进行UI更新。
 
onPostExecute(Result) 
当doInBackground(Params...)执行完毕,并通过return进行返回时,这个方法就会马上被调用。返回的数据会被作为该方法的参数传递过来,该方法是在主线程中运行,可以利用返回的数据进行UI更新操作,如提醒任务执行的结果或关闭掉进度条对话框等。
 
这几个方法的调用顺序:
需要进度更新 : onPreExecute() –> doInBackground() –> publishProgress() –> onProgressUpdate() –> onPostExecute()
不需要进度更新 :onPreExecute() –> doInBackground() –> onPostExecute()
除了上面的几个核心方法外,AsyncTask还提供了onCancelled()方法,该方法运行在主线程,当异步任务取消时,该方法就会被调用,这个时候onPostExecute(Result)就不会被调用。
NOTE :AsyncTask中的cancel()方法并不是真正去取消任务,只是将这个任务设置为取消状态,需要在doInBackgroud(Params…)方法中判断终止任务。
 
使用 定义任务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 class  DownloadTask  extends  AsyncTask <Void , Integer , Boolean >     @Override      protected  void  onPreExecute ()           progressDialog.show();     }     @Override      protected  Boolean doInBackground (Void... params)           try  {              while  (true ) {                 int  downloadPercent = doDownload();                 publishProgress(downloadPercent);                 if  (downloadPercent >= 100 ) {                     break ;                 }             }         } catch  (Exception e) {             return  false ;         }         return  true ;     }     @Override      protected  void  onProgressUpdate (Integer... values)           progressDialog.setMessage("当前下载进度:"  + values[0 ] + "%" );     }     @Override      protected  void  onPostExecute (Boolean result)           progressDialog.dismiss();         if  (result) {             Toast.makeText(context, "下载成功" , Toast.LENGTH_SHORT).show();         } else  {             Toast.makeText(context, "下载失败" , Toast.LENGTH_SHORT).show();         }     } } 
执行任务:
1 new  DownloadTask().execute();
注意事项 :
AsyncTask实例必须在主线程中创建。
execute(Params…)方法必须在主线程中调用。
不要手动去调用onPreExecute(),onPostExecute(Result),doInBackground(Params…), onProgressUpdate(Progress…)这几个方法。
一个任务实例只能执行一次,如果执行第二次将会抛出异常。 
 
源码解析(API 28) 全局线程池配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 private  static  final  int  CPU_COUNT = Runtime.getRuntime().availableProcessors();private  static  final  int  CORE_POOL_SIZE = Math.max(2 , Math.min(CPU_COUNT - 1 , 4 ));private  static  final  int  MAXIMUM_POOL_SIZE = CPU_COUNT * 2  + 1 ;private  static  final  int  KEEP_ALIVE_SECONDS = 30 ;private  static  final  ThreadFactory sThreadFactory = new  ThreadFactory() {    private  final  AtomicInteger mCount = new  AtomicInteger(1 );     public  Thread newThread (Runnable r)           return  new  Thread(r, "AsyncTask #"  + mCount.getAndIncrement());     } }; private  static  final  BlockingQueue<Runnable> sPoolWorkQueue =    new  LinkedBlockingQueue<Runnable>(128 ); public  static  final  Executor THREAD_POOL_EXECUTOR;static  {    ThreadPoolExecutor threadPoolExecutor = new  ThreadPoolExecutor(         CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,         sPoolWorkQueue, sThreadFactory);     threadPoolExecutor.allowCoreThreadTimeOut(true );     THREAD_POOL_EXECUTOR = threadPoolExecutor; } 
全局顺序任务调度器配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public  static  final  Executor SERIAL_EXECUTOR = new  SerialExecutor();private  static  volatile  Executor sDefaultExecutor = SERIAL_EXECUTOR;private  static  InternalHandler sHandler;private  static  class  SerialExecutor  implements  Executor           final  ArrayDeque<Runnable> mTasks = new  ArrayDeque<Runnable>();     Runnable mActive;     public  synchronized  void  execute (final  Runnable r)                    mTasks.offer(new  Runnable() {             public  void  run ()                   try  {                     r.run();                 } finally  {                     scheduleNext();                 }             }         });                  if  (mActive == null ) {             scheduleNext();         }     }     protected  synchronized  void  scheduleNext ()                    if  ((mActive = mTasks.poll()) != null ) {             THREAD_POOL_EXECUTOR.execute(mActive);         }     } } 
构建任务 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 public  AsyncTask ()      this ((Looper) null ); } public  AsyncTask (@Nullable Handler handler)      this (handler != null  ? handler.getLooper() : null ); } public  AsyncTask (@Nullable Looper callbackLooper)      mHandler = callbackLooper == null  || callbackLooper == Looper.getMainLooper()         ? getMainHandler()         : new  Handler(callbackLooper);     mWorker = new  WorkerRunnable<Params, Result>() {         public  Result call ()  throws  Exception              mTaskInvoked.set(true );             Result result = null ;             try  {                 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                                  result = doInBackground(mParams);                 Binder.flushPendingCommands();             } catch  (Throwable tr) {                 mCancelled.set(true );                 throw  tr;             } finally  {                 postResult(result);             }             return  result;         }     };     mFuture = new  FutureTask<Result>(mWorker) {         @Override          protected  void  done ()               try  {                 postResultIfNotInvoked(get());             } catch  (InterruptedException e) {                 android.util.Log.w(LOG_TAG, e);             } catch  (ExecutionException e) {                 throw  new  RuntimeException("An error occurred while executing doInBackground()" , e.getCause());             } catch  (CancellationException e) {                 postResultIfNotInvoked(null );             }         }     }; } private  static  abstract  class  WorkerRunnable <Params , Result > implements  Callable <Result >     Params[] mParams; } private  void  postResultIfNotInvoked (Result result)      final  boolean  wasTaskInvoked = mTaskInvoked.get();     if  (!wasTaskInvoked) {         postResult(result);     } } private  Result postResult (Result result)      @SuppressWarnings ("unchecked" )     Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new  AsyncTaskResult<Result>(this , result));     message.sendToTarget();     return  result; } 
说明:在构造方法中,主要是初始化了mWorker和mFuture两个成员变量,mWorker是一个Callable对象,作为mFuture的构建参数。在mWorker的call()方法中,会调用doInBackground()执行耗时任务,并将执行结果通过postResult(result)传递给内部Handler跳转到主线程中。
执行任务 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @MainThread public  final  AsyncTask<Params, Progress, Result> execute (Params... params)      return  executeOnExecutor(sDefaultExecutor, params); } @MainThread public  final  AsyncTask<Params, Progress, Result> executeOnExecutor (Executor exec, Params... params)      if  (mStatus != Status.PENDING) {         switch  (mStatus) {             case  RUNNING:                 throw  new  IllegalStateException("Cannot execute task:"                                                  + " the task is already running." );             case  FINISHED:                 throw  new  IllegalStateException("Cannot execute task:"                                                  + " the task has already been executed "                                                  + "(a task can be executed only once)" );         }     }     mStatus = Status.RUNNING;     onPreExecute();     mWorker.mParams = params;          exec.execute(mFuture);     return  this ; } 
说明:在执行execute(Params)方法时,会调用executeOnExecutor并传入一个sDefaultExecutor,这是前面创建的一个全局的SerialExecutor,它用于控制任务的串行执行。
线程切换 :
mWorker中call()方法,会先执行doInBackground,并将执行结果通过postResult()发送到主线程。
 
1 2 3 4 5 6 private  Result postResult (Result result)           Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new  AsyncTaskResult<Result>(this , result));     message.sendToTarget();     return  result; } 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 private  static  class  InternalHandler  extends  Handler      public  InternalHandler (Looper looper)           super (looper);     }     @SuppressWarnings ({"unchecked" , "RawUseOfParameterizedType" })     @Override      public  void  handleMessage (Message msg)           AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;         switch  (msg.what) {             case  MESSAGE_POST_RESULT:                                  result.mTask.finish(result.mData[0 ]);                 break ;             case  MESSAGE_POST_PROGRESS:                                  result.mTask.onProgressUpdate(result.mData);                 break ;         }     } } 
在收到MESSAGE_POST_RESULT消息时,会调用finish方法。
1 2 3 4 5 6 7 8 private  void  finish (Result result)      if  (isCancelled()) {         onCancelled(result);     } else  {         onPostExecute(result);     }     mStatus = Status.FINISHED; } 
说明:如果任务取消了,就会回调onCancelled(result)方法,否则回调onPostExecute(result)。
AsyncTask的串行和并行 :
从源码可以看出,默认情况下AsyncTask的执行效果是串行的,因为使用SerialExecutor类来保证队列的串行。如果想使用并行执行任务,可以跳过SerialExecutor类,使用executeOnExecutor()来执行任务。
 
AsyncTask使用不当的后果 
内存泄漏 
如果AsyncTask被声明为Activity的非静态内部类,那么AsyncTask会保留一个对创建了AsyncTask的Activity的引用。如果Activity已经被销毁,AsyncTask的后台线程还在执行,它将继续在内存里保留这个引用,导致Activity无法被回收,引起内存泄露。所以最好在Activity的onDestroy()方法中调用cancel()来取消任务。
 
结果丢失 
屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask(非静态的内部类)会持有一个之前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。
 
 
为什么AsyncTask必须在主线程实例化 
在Android 5.1(API 22)之前,AsyncTask内部用于控制线程切换的sHandler的初始化代码:
1 private  static  final  InternalHandler sHandler = new  InternalHandler();
这就导致AsyncTask必须在主线程创建,才能让sHandler与主线程的Looper关联,来实现线程切换的相关逻辑。
在Android 5.1(API 22)之后,sHandler的初始化代码:
1 2 3 4 5 6 7 8 9 10 11 private  static  InternalHandler sHandler;private  static  Handler getMainHandler ()      synchronized  (AsyncTask.class) {         if  (sHandler == null ) {             sHandler = new  InternalHandler(Looper.getMainLooper());         }         return  sHandler;     } } 
从代码可见,InternalHandler在实例化的时候会传入Looper.getMainLooper(),那么AsyncTask不是就可以在子线程中创建?经测试,在子线程创建不会报错。
在API28的源码中,构造方法的注释:
1 2 3 4 5 6 public  AsyncTask ()      this ((Looper) null ); } 
注释指出必须在主线程调用该构造方法,可能是为了兼容旧版的系统。
 
参考链接 
AsyncTask 你真的了解AsyncTask? AsyncTask详解 关于AsyncTask的一次深度解析 Android源码分析—带你认识不一样的AsyncTask AsyncTask的原理 及其源码分析 Android AsyncTask 源码解析