今天我们来说说AsyncTask版本之间的差异,我们现在使用AsyncTask通常会使用如下方式:
class DownloadTask extends AsyncTask<Void,Integer,String>{
@Override
protected String doInBackground(Void... params) {
return null;
}
}
然后我们怎么执行任务呢:
new DownloadTask().execute();
今天我们通过源码来看看AsyncTasik版本之间的差异,我们点进去execute()这个方法:
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
我们可以看到execute()这个方法实际上是调用了executeOnExecutor(sDefaultExecutor, params)这个方法,这个方法接收两个参数,我们重点看第一个参数,这是一个Executor对象,我们看看它是在哪定义的
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
我们看到sDefaultExecutor 的值是一个常量,然后我们继续看这个常量是什么
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
这个常量是一个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);
}
}
}
重点看scheduleNext这个方法,里面有个THREAD_POOL_EXECUTOR对象,这是什么,我们继续找
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
可以看到这里使用了线程池,其中常量定义如下:
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;
这是3.0之后的AsyncTask的源代码,每次当一个任务执行完毕后,下一个任务才会得到执行,SerialExecutor模仿的是单一线程池的效果,如果我们快速地启动了很多任务,同一时刻只会有一个线程正在执行,其余的均处于等待状态。
但是之前的代码不是这样的,在Android 3.0之前是并没有SerialExecutor这个类的,那个时候是直接在AsyncTask中构建了一个sExecutor常量,并对线程池总大小,同一时刻能够运行的线程数做了规定
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final int KEEP_ALIVE = 10;
……
private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
可以看到,这里规定同一时刻能够运行的线程数为5个,线程池总大小为128。也就是说当我们启动了10个任务时,只有5个任务能够立刻执行,另外的5个任务则需要等待,当有一个任务执行完毕后,第6个任务才会启动,以此类推。而线程池中最大能存放的线程数是128个,当我们尝试去添加第129个任务时,程序就会崩溃。
因此在3.0版本中AsyncTask的改动还是挺大的,在3.0之前的AsyncTask可以同时有5个任务在执行,而3.0之后的AsyncTask同时只能有1个任务在执行。为什么升级之后可以同时执行的任务数反而变少了呢?这是因为更新后的AsyncTask已变得更加灵活,如果不想使用默认的线程池,还可以自由地进行配置。比如使用如下的代码来启动任务:
Executor exec = new ThreadPoolExecutor(15, 200, 10,
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
new DownloadTask().executeOnExecutor(exec);
这样就可以使用我们自定义的一个Executor来执行任务,而不是使用SerialExecutor。上述代码的效果允许在同一时刻有15个任务正在执行,并且最多能够存储200个任务。
下面对AsyncTask进行一下总结: