[Android] AsyncTask源码解析

常用例子

本文依照以下常用例子展开:

AsyncTask的使用方法太常见了,这里不做详述。值得注意的是AsyncTask有以下用法:

可以通过get()方法来获得AsyncTask的运行结果,这是通过java.util.concurrent的FutureTask类来完成的。AsyncTask类依赖于java.util.concurrent,task的执行和调度都由FutureTask、Executor、LinkedBlockingQueue等类来完成,下文会对其展开介绍。

源码解析

AsyncTask的状态

AsyncTask有三种状态:

对象初始化完毕后为PENDING状态,execute()被执行时转变成RUNNING状态,onPostExecute执行后变成FINISHED状态。execute()方法仅可以在task为PENDING状态下调用,否则会抛出IllegalStateException。

AsyncTask的初始化

AsyncTask有很多静态属性:

其中:

sThreadFactory:供THREAD_POOL_EXECUTOR使用。为每个thread设定自增的name。

sPoolWorkQueue:供THREAD_POOL_EXECUTOR使用。

THREAD_POOL_EXECUTOR:供SerialExecutor使用,task真正执行的场所。

SERIAL_EXECUTOR:默认executor的实现,下文会对其详述。

sHandler:初始化时注入主线程的Looper,接收MESSAGE_POST_RESULT和MESSAGE_POST_PROGRESS消息。

其中SerialExecutor的实现如下所示:

代码逻辑如下所示:

  1. 当SerialExecutor对象的execute(runnable)执行时,首先会将runnable对象包装一下,然后放到一个FIFO的队列mTasks当中。如果是首次执行,那么scheduleNext()方法会被调用。
  2. 在scheduleNext()方法中,mTasks中的runnable被取出并赋给mActive变量,然后将mActive放到THREAD_POOL_EXECUTOR中执行。
  3. 在THREAD_POOL_EXECUTOR中调用run()方法,然后再次调用scheduleNext()方法取出下一个runnable。

接下来看一下AsyncTask的初始化方法:

WorkerRunnable的源码如下所示:

可以看到WorkerRunnable继承于Callable,因此可以放到Executor中执行。因此mWorker这个匿名类的call方法会在Executor中调用。
首先将mTaskInvoked设置为true。mTaskInvoked用于检查当前的mWorker是否已经被执行(有可能还没执行就cancel了)。然后设置一下线程优先级,最后调用postResult()方法向sHandler发送MESSAGE_POST_RESULT消息。

接下来看mFuture。mFuture是一个FutureTask对象,可以通过调用mFuture.get()来堵塞式地等待task的执行结果,详情可以参考这里。done()方法会在mWorker结束(无论是cancel还是正常finish)时调用。其中postResultIfNotInvoked()源码如下所示:

如果当前mWorker没有被执行过,则执行postResult()方法。这里保证了无论mWorker是否正常结束,主线程的回调依然会正常执行。

AsyncTask的执行

通过类似调用new DownloadFilesTask().execute(url1, url2, url3);可以执行一个AsyncTask。execute方法的源码如下所示:

代码逻辑见注释。结合前文对mFuture和mWorker的讲解,可以画出AsyncTask的执行流程图: