安卓 - 源码 - AsyncTask

简介

AsyncTask 是一个 Thread 和 Handler 的助手类。
通过该类,可以轻松的创建 需要把结果发布到UI线程的短期后台操作。
(长时间后台操作推选使用 java.util.concurrent 的API)

在API 11前,线程池是一个普通的ThreadPoolExecutor,支持并发

new ThreadPoolExecutor(5, 128, 10, TimeUnit.SECONDS, 
          LinkedBlockingQueue<Runnable>(10), ThreadFactory);

在API 11后,线程池是一个维护了Runnable队列的SerialExecutor,支持串行

new SerialExecutor();

注意到的是,SerialExecutor内部实际是通过一个支持并发的线程池工作的:

public static final Executor THREAD_POOL_EXECUTOR;
static {
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
              [2,4], CPU*2+1, 30, TimeUnit.SECONDS,
              LinkedBlockingQueue<Runnable>(128), ThreadFactory);
    threadPoolExecutor.allowCoreThreadTimeOut(true);
    THREAD_POOL_EXECUTOR = threadPoolExecutor;
}

而AsyncTask支持通过executeOnExecutor执行在指定的线程池,所以如果需要执行并发任务的时候,可以直接使用

executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

而无需重新自定义线程池。


基本行为

AsyncTask的行为被定义为2块:

  • 泛型参数 <Params, Progress, Result>
    用于定义AsyncTask执行时使用的3种参数的类型:

    public abstract class AsyncTask<Params, Progress, Result> {...}
    
    Params   :执行时传入的参数的类型;
    Progress :进度更新时传出的参数的类型;
    Result   :执行完成时返回的参数的类型;
    
  • 执行步骤
    AsyncTask执行时主要的4个步骤方法:

    @MainThread
    protected void onPreExecute() {}
    :在后台任务开始前的初始化方法,执行在UI线程,可以用于设置任务
    
    
    @WorkerThread
    protected abstract Result doInBackground(Params... params){...}
    :onPreExecute之后马上执行,后台任务的执行方法,也是AsyncTask的核心方法,在后台线程中执行
    执行过程中,可以使用publishProgress通知后台任务的进度更新
    执行结束时,返回的结果会作为onPostExecute的参数
    
    
    @MainThread
    protected void onProgressUpdate(Progress... values) {...}
    :调用publishProgress后执行,执行在UI线程,用于执行后台进度变更时需要变化的逻辑
    
    
    @MainThread
    protected void onPostExecute(Result result) {...}
    :后台任务完成时调用,执行在UI线程,用于接收执行结果处理后台任务执行完成的逻辑
    

工作原理

AsyncTask主要的工作可以概括成:

  1. 后台耗时任务,AsyncTask的工作主体
  2. 在UI线程的任务进度通知以及任务完成通知

在AsyncTask的说明中提及,该类只是一个Thread和Handler的辅助类,而不是一个标准的线程操作框架:

AsyncTask is designed to be a helper class around {@link Thread} and {@link Handler}
and does not constitute a generic threading framework.

其中涉及到的内容:

  1. Thread :后台工作的所在线程,由预置或自定义线程池维护
  2. Handler:从后台线程切换到UI线程的核心,完成所有后台任务中对通知UI线程的通知操作

线程切换

AsyncTask中对Thread和Handler的处理切换,主要由以下的对象完成:

private final Handler mHandler;
:AsyncTask对象的成员,指向AsyncTask静态成员sHandler


private static InternalHandler sHandler 
          = new InternalHandler(Looper.getMainLooper())
:传入Looper.getMainLooper()说明运行在主线程
负责AsyncTask从工作线程切换到主线程,执行如onProgressUpdate等方法


private static class InternalHandler extends Handler {
      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;
             }
       }
}
:AsyncTaskResult<?> result在下面分析
这里主要关注sHandler的工作内容,sHandler处理的工作主要有:
1.MESSAGE_POST_RESULT   : 对应方法为onPostExecute()
2.MESSAGE_POST_PROGRESS : 对应方法为onProgressUpdate()
在该处可以推断出:推送到sHandler的消息基本来自子线程,通过sHandler实现UI线程的切换


private static class AsyncTaskResult<Data> {
      final AsyncTask mTask;
      final Data[] mData;
      AsyncTaskResult(AsyncTask task, Data... data) {
            mTask = task;
            mData = data;
      }
 }
:推送到sHandler的消息的数据封装,主要封装了当前的AsyncTask和操作参数
1.mTask:需要执行UI线程任务的AsyncTask对象
2.mData:AsyncTask执行UI线程任务的参数,在推送<Progress>参数时,可以是多参数的

以上的部分完成UI线程的工作任务,且反映了:
AsyncTask 的 onPostExecute() 和 onProgressUpdate() 运行在UI线程依赖的是Handler机制。


执行任务

  1. 从execute开始
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
      return executeOnExecutor(sDefaultExecutor, params);
}
:调用execute方法时,实际上调用了executeOnExecutor方法
传入的线程池,则是上面简介中提到的SerialExecutor,一个串行执行任务的线程池


@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) {

      if (mStatus != Status.PENDING) ... ...
      :检查AsyncTask实例的运行状态
      AsyncTask每一个实例,只允许执行一次(execute)
      除了PENDING,其余状态都会抛出IllegalStateException


      mStatus = Status.RUNNING;
      onPreExecute();
      :修改为运行中状态,在UI线程中执行AsyncTask的预处理方法
       

      mWorker.mParams = params;
      exec.execute(mFuture);
      :这里涉及到了一个mWorker对象,属于后台线程运行部分,下一部分说明
      大体上,mWorker是一个Callable,负责AsyncTask的后台任务调用过程


      return this;
}
:executeOnExecutor大体上负责了2个内容:
1.判断当前执行状态
2.使用传入的线程池,执行AsyncTask的后台任务

  1. 执行后台任务
    使用传入的线程池执行AsyncTask的后台任务,具体的执行流程,封装在mWorker
private final WorkerRunnable<Params, Result> mWorker;
private static abstract class WorkerRunnable<Params, Result> 
      implements Callable<Result> {
      Params[] mParams;
}
:mWorker是 WorkerRunnable类的实例
本质上是一个保存了Params参数的Callable对象


mWorker = new WorkerRunnable<Params, Result>() {
      public Result call() throws Exception {

            mTaskInvoked.set(true);
            :设置调用状态为已被调用
            在该状态设置前,doInBackground被标识为未调用
            
            Result result = null;
            try {
                  Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                  result = doInBackground(mParams);
                  :设置线程优先级为后台线程,执行doInBackground

            } catch (Throwable tr) {
                  mCancelled.set(true);
                  :当发生异常时,设置AsyncTask取消状态为已取消

                  throw tr;
            } finally {
                  postResult(result);
                  :发送执行结果,属于执行完成的部分,后面介绍

            }

            return result;
      }
};
:mWorker负责处理了doInBackground的逻辑
以及doInBackground完成后调用postResult发送执行结果


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(..., e.getCause());
            } catch (CancellationException e) {
                  postResultIfNotInvoked(null);
            }
      }
};
private void postResultIfNotInvoked(Result result) {
      final boolean wasTaskInvoked = mTaskInvoked.get();
      if (!wasTaskInvoked) {
            postResult(result);
      }
}
:mFuture是包裹mWorker的FutureTask对象
这里的逻辑基本上只有一种情况会发生,即 doInBackground抛出异常或错误,
导致 get() 方法调用时抛出 ExecutionException,然后 done() 方法抛出 RuntimeException


  1. 发送执行结果
private Handler getHandler() {
      return mHandler;
}
private Result postResult(Result result) {
      Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                  new AsyncTaskResult<Result>(this, result));
      message.sendToTarget();
      return result;
}
:把执行结果发送到mHandler,意味着在主线程执行


case MESSAGE_POST_RESULT:
      result.mTask.finish(result.mData[0]);
      break;
:mHandler处理执行结果的逻辑,调用了mTask的finish方法


public final boolean isCancelled() {
      return mCancelled.get();
}
private void finish(Result result) {
      if (isCancelled()) {
            onCancelled(result);
      } else {
            onPostExecute(result);
      }
      mStatus = Status.FINISHED;
}
:根据执行状态选择需要调用的方法
1.onCancelled() 即任务被取消
2.onPostExecute() 即任务完成

mCancelled为true的情况有2种
1.调用了AsyncTask的cancel()方法取消任务
2.doInBackground()的过程中抛出异常,导致任务被取消


@MainThread
protected void onCancelled(Result result) {
      onCancelled();
}  
@MainThread
protected void onCancelled() {
}
@MainThread
protected void onPostExecute(Result result) {
}
:执行结果的方法都可以根据需求重写

以上就是AsyncTask的工作过程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章