AsyncTask是Android系统封装的多线程工具类。它管理着线程池,控制着合理的执行中的线程的个数。同时,它还提供了,执行前,执行中,执行后的接口,方便线程的管理与使用。
下面,我们来阅读一下AsyncTask的源码,才疏学浅,不能多么深刻的理解,但相信在阅读过程中,能有一些意想不到的收获。
public abstract class AsyncTask<Params, Progress, Result> { private static final String LOG_TAG = "AsyncTask"; private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); private static final int CORE_POOL_SIZE = CPU_COUNT + 1; private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; private static final int KEEP_ALIVE = 1; 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);
首先,我们可以看到,AsyncTask是一个虚类。成员变量非常多,我们一个一个来认识。
LOG_TAG没什么好说的。
CPU_COUNT顾名思义就是当前设备的CPU数量。其中Runtime是让app获取虚拟机运行环境的类,不能直接创建,但可以获取它的引用。我们从中取得可用的处理器有多少。
接下来的CORE_POOL_SIZE和MAXIMUM_POOL_SIZE即是核心线程数和最大线程数。
KEEP_ALIVE在ThreadPoolExecutor中有所描述:keepAliveTime when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating。
然后,是一个静态私有的线程工厂。它负责新建线程,其中mCount 是一个原子Integer。虽然没看后面,但我猜想,由于线程工厂sThreadFactory是静态的,可能会有多个线程来读写这个sThreadFactory.mCount因此,它需要是一个线程安全的原子数。getAndIncrement()是后置递增的方法,效果类似于i++,但它本身是线程安全的,而i++不是线程安全的。通过newThread方法,sThreadFactory即新建了以当前已有线程数为名字的新线程。
sPoolWorkQueue是一个BlockingQueue(阻塞队列)。即如果队列为空,我的取操作将会被阻塞,直到有元素进入队列为止;如果队列为满,我的写入操作将会被阻塞,直接有元素被取走留出空位为止。其他的则和基本队列一样,遵循FIFO原则。而LinkedBlockingQueue则是在构造方法中可以很方便的确定它的长度。这个作为正在工作的线程队列是一个很合适的数据结构。
public static final Executor SERIAL_EXECUTOR = new SerialExecutor(); 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); } } }
接下来,AsyncTask定义了一个特殊的Executor并创建了它的实例。看看这个类,我们就会发现,其中有一个容器叫ArrayDeque,用来存放我们的任务。
它是一个可以调整大小的双端队列
数组双端队列没有容量限制,使他们增长为必要支持使用。
它们不是线程安全的;如果没有外部同步。
不支持多线程并发访问。
null元素被禁止使用在数组deques。
它们要比堆栈Stack和LinkedList快。mTasks.offe()的主要作用是从双端队列的尾部insert元素,而mTasks.poll()的作用是从双端队列头部取出元素。
有了以上补充知识,现在我们来看看这个类到底是如何工作的。当执行器执行任务时,首先,我们将一个新的Runnable推入任务队列中。如果任务当前活动任务为空则执行scheduleNext()方法,执行队列中的下一个任务。在scheduleNext()方法中,我们可以看到代码先从mTasks中poll出队首的任务,如果不为空,则让线程池去执行它。执行的过程是先执行任务本身的工作(即r.run()),执行完成后,执行scheduleNext()去寻找下一个任务。
private static final int MESSAGE_POST_RESULT = 0x1; private static final int MESSAGE_POST_PROGRESS = 0x2; private static final InternalHandler sHandler = new InternalHandler(); private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; private static class InternalHandler extends Handler { @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"}) @Override public void handleMessage(Message msg) { AsyncTaskResult result = (AsyncTaskResult) msg.obj; switch (msg.what) { case MESSAGE_POST_RESULT: // There is only one result result.mTask.finish(result.mData[0]); break; case MESSAGE_POST_PROGRESS: result.mTask.onProgressUpdate(result.mData); break; } } }
这里定义了一个handler,用于接收进行中的线程发回来的消息。主要接收其他线程完成,和其他线程进度通知两类消息。
我们先来看看AsyncTaskResult类
@SuppressWarnings({"RawUseOfParameterizedType"}) private static class AsyncTaskResult<Data> { final AsyncTask mTask; final Data[] mData; AsyncTaskResult(AsyncTask task, Data... data) { mTask = task; mData = data; } }
AsyncTaskResult中有两个成员,一个是AsyncTaskResult封装的任务,另一个Data应该是任务的进度。
result.mTask.finish(result.mData[0])的代码:
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
任务在取消或结束时会有这样两个方法。方法本身内容是空的,我们可以继承AsyncTask,重写这两个方法满足业务逻辑。
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; private final WorkerRunnable<Params, Result> mWorker; private final FutureTask<Result> mFuture;
FutureTask
一个可取消的异步运算,这个类实现了Fututre的接口,可以开始和取消一个运算操作,判断这个操作是否已经完成了,和重新得到运算操作的结果。运算的结果仅仅在运算结束完成后被恢复,get的方法将会阻塞程序,如果这个运算操作还没有完成的话。一旦运算操作完成了,这个操作就不能重新开始或者取消了。
这个类过去常常用于包装一个Callable or Runnable 类的。因为FutureTask实现了runnable借口,一个FutureTask可以实现线程池中的execution方法。
除了是一个单独的类之外,这个类还提供了可能有之用途定制任务classed的保护功能.
private final AtomicBoolean mCancelled = new AtomicBoolean(); private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
接下面就是两个线程安全的Boolean型,记录任务是否已被取消和任务是否已被调用,两个状态。
/** * Indicates the current status of the task. Each status will be set only once * during the lifetime of a task. */ public enum Status { /** * Indicates that the task has not been executed yet. */ PENDING, /** * Indicates that the task is running. */ RUNNING, /** * Indicates that {@link AsyncTask#onPostExecute} has finished. */ FINISHED, }
这里一个枚举型,用来区分任务的状态,未开始、已开始、已完成。
以上AsyncTask的成员变量就阅读完毕。接下来,开始看AsyncTask中的方法。
/** @hide Used to force static handler to be created. */ public static void init() { sHandler.getLooper(); } /** @hide */ public static void setDefaultExecutor(Executor exec) { sDefaultExecutor = exec; }
前两个方法比较简单易懂。用@hide做了标记,即外部不可调用,只在内部进行的一些初始化。
接下来,我们将开始阅读AsyncTask的构造方法。代码不多,却非常重要。
/** * Creates a new asynchronous task. This constructor must be invoked on the UI thread. */ public AsyncTask() { mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked return postResult(doInBackground(mParams)); } }; 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 occured while executing doInBackground()", e.getCause()); } catch (CancellationException e) { postResultIfNotInvoked(null); } } }; }
这个方法从整体上来看,就是创建了WorkerRunnable和FutureTask两个类的对象。我们先来看WorkerRunnable类的创建:
mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked return postResult(doInBackground(mParams)); } };
上面提到WorkerRunnable类满足了Callable的接口,程序在这里实现了它的call方法。先将任务被调用的标志位设为true,然后将当前线程设为后台线程。doInBackground是个虚方法,没有具体实现,交由子类去实现,使用过AsyncTask的都无需多说这一点,将doInBackground的结果给处理结果的方法postResult(Result r),我们来看看postResult(Result r)的实现。
private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; }
代码会用Result建一个AsyncTaskResult对象,将任务和数据保存在一起,然后作为结果用message发送给sHandler。sHandler前面介绍过是一个将任务执行的进度或结果返回的类。以上WorkerRunnable就创建完成了。接下来再看FutureTask的创建过程。
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 occured while executing doInBackground()", e.getCause()); } catch (CancellationException e) { postResultIfNotInvoked(null); } } };
postResultIfNotInvoked()方法和postResult()方法几乎一样,只是在调用前,检查了mTaskInvoked的值。如果任务被取消,则会将result设为null。
接下来看到一个常用的方法
public final boolean cancel(boolean mayInterruptIfRunning) { mCancelled.set(true); return mFuture.cancel(mayInterruptIfRunning); }
由于语义化命名,我们非常容易理解,这个方法,即是取消任务。需要传入一个boolean值,表示,如果它正在运行,是否需要中断。
后面有一些简单的方法比如isCancelled(),就是取前面介绍的mCancelled的值,在此就不赘述了。我们接下来看最核心的方法。execute();
/* <p>This method must be invoked on the UI thread. * * @param params The parameters of the task. * * @return This instance of AsyncTask. * * @throws IllegalStateException If {@link #getStatus()} returns either * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}. * * @see #executeOnExecutor(java.util.concurrent.Executor, Object[]) * @see #execute(Runnable) */ public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }
/* <p>This method must be invoked on the UI thread. * * @param exec The executor to use. {@link #THREAD_POOL_EXECUTOR} is available as a * convenient process-wide thread pool for tasks that are loosely coupled. * @param params The parameters of the task. * * @return This instance of AsyncTask. * * @throws IllegalStateException If {@link #getStatus()} returns either * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}. * * @see #execute(Object[]) */ 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; }
方法先做了一个判断,如果任务不是未执行状态,根据任务当前的状态,抛出异常。之后将当前的任务状态改为正在运行,执行 onPreExecute();这个空方法,并将参数传给mWorker,由默认的执行器执行。默认执行器SerialExecutor执行这个任务。这又回到了SerialExecutor的初始化,里面包含了执行任务的方法,这个在前面已经介绍过了。
到这里,AsyncTask类的基本流程就阅读完毕了。但是里面还有一些类的工作原理不是特别清楚如FutureTask等,有待探究。
Done!