AsyncTask默认一次只能执行一个任务
AsyncTask默认是使用线程池实现异步操作的,如果你调用的是execute()方法,那么:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
sDefaultExecutor是里面的一个static的默认线程池:
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
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);
}
}
}
sDefaultExecutor其实就是SerialExecutor,从名字看就知道是一个序列线程池实现,也就是说传进来的任务是一个一个派对执行的,上一个任务没执行完成,新进来的任务会加入队列并等待直到上一个任务执行完成之后才开始执行,里面不是维护了一个ArrayDeque双端队列吗;而如果你不想一个一个执行任务想让任务并发执行也很简单,不用调用execute()而调用executeOnExecutor()方法,可从外部传一个你自定义的线程池,那么就能让任务并发执行了
AsyncTask异步操作
AsyncTask之所以能做到异步就是它把任务放到一个线程池中去单独开一个线程来执行,而且AsyncTask还不会造成UI卡顿,为啥?我们平常一直以为不想造成UI卡顿那就不在主线程中执行耗时任务,而把耗时任务单独开一个Thread来执行,如果只是少量的耗时任务,开少量的Thread来执行那当然没问题,但是当你开的Thread很多的时候依然会造成UI卡顿,原因之一是开java线程很耗费内存资源,其二就是线程竞争:我们的UI线程是一个普通线程,而我们new出来的Thread也是一个普通线程,这二者的线程优先级其实是一样的,所以当开的线程很多的时候有可能线程竞争导致系统先执行我们自己开的Thread而主线程暂时等待执行,此时就造成了界面卡顿;但是AsyncTask不会有这种情况发生,为啥?因为:
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);
}
}
};
}
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()方法,那么其实它里面的实现也是调用executeOnExecutor(Executor, Params…),只不过默认传入sDefaultExecutor参数,然后会用Future来执行线程,Future线程执行的时候会调用mWorker的call方法,call方法里面就做了doInBackground(),精髓来了,在doInBackground()之前多了一句Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);把当前执行的任务线程的优先级设置成了后台线程THREAD_PRIORITY_BACKGROUND,看看注释是怎么解释它的:
/**
* Standard priority background threads. This gives your thread a slightly
* lower than normal priority, so that it will have less chance of impacting
* the responsiveness of the user interface.
* Use with {@link #setThreadPriority(int)} and
* {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
* {@link java.lang.Thread} class.
*/
public static final int THREAD_PRIORITY_BACKGROUND = 10;
说明THREAD_PRIORITY_BACKGROUND 是后台线程,优先级要比正常线程(normal priority)要低,所以执行的重要性更低,在线程竞争的时候肯定是先执行正常线程在执行后台线程,由此就完全不会阻塞UI主线程了
AsyncTask中几个方法
onPreExecute,onPostExecute(Result),onProgressUpdate(Progress…),onCancelled(),在UI线程中执行,这些都是通过Handler实现的,就不细说了
doInBackground是在线程中执行的,刚才上面也看到了,在Future执行的时候就会被执行