AsyncTask是Android的异步类……恩,大家应该都知道,直接分析吧。开始之前如果对Android的Callable,Future不了解的话可以先看看这篇文章 Java并发编程:Callable、Future和FutureTask
首先看看简单的用法,我自定义了一个TestAsyncTask:
class TestAsyncTask extends AsyncTask<String, Integer, Long> {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected void onPostExecute(Long aLong) {
super.onPostExecute(aLong);
}
@Override
protected Long doInBackground(String... params) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}
这里简单说一下,这里用到了三个泛型,第一个代表我们执行的任务需要的参数,就是doInBackground里面的参数,第二个泛型是用来更新进度的时候使用的,第三个泛型用来指定返回类型。
用的时候呢new TestAsyncTask().execute("helloWorld");
那么就从new开始分析先看一下AsyncTask的构造函数:
public AsyncTask() {
//创建一个WorkerRunnable,这个对象实现了Callable接口
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
//执行doInBackground
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(result);
}
};
//创建一个mFuture
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 occurred while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
首先先创建了一个创建一个WorkerRunnable对象,看源码可以知道这个对象实现了Callable接口,并且把任务封装在了call方法里面,这个方法主要就是执行了doInBackground方法.
然后从、又创建了一个FutureTask对象,看过上面那个文章的应该知道FutureTask既可以当Runnable使用又可以当Future使用。new FutureTask<Result>(mWorker)
,这里的Result就是任务执行完之后的返回值的类型,其实FutureTask只是包装了一下mWorker,所以我们要执行的任务就是FutureTask类,主要任务就是执行doInbackground,并把执行结果交给Future。
下面继续看execute(“helloWorld”)方法:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
这个方法实际上是调用了executeOnExecutor方法,我们一会再看这个方法,先看一下传入这个方法的两个参数:sDefaultExecutor
,和params
先看看sDefaultExecutor的定义:
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
sDefaultExecutor 就是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);
}
}
}
可以看出SerialExecutor 中有一个任务队列mTasks
,每次执行SerialExecutor
的execute
方法都会将任务加入这个任务队列,如果当前没有任务在执行,那么久取出一个任务让THREAD_POOL_EXECUTOR执行。THREAD_POOL_EXECUTOR比较简单,
params比较简单,就是
new TestAsyncTask().execute("helloWorld");
的时候传入的“hello world”
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
可以看出THREAD_POOL_EXECUTOR只是一个常量池。
这样SerialExecutor 的任务就清楚了,将消息放入消息队列,并一个一个地串行地取出并交给THREAD_POOL_EXECUTOR执行
下面接着分析executeOnExecutor,
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()
onPreExecute();
//把需要的参数传给mWorker,也就是传给FutherTask即mFuture
mWorker.mParams = params;
//这里的exec就是我们在execute方法中传给executeOnExecutor的第一个参数也就是sDefaultExecutor
exec.execute(mFuture);
return this;
}
这段代码首先判断任务是否正在执行或者已经执行完了,如果是,那就抛出异常,否则执行onPreExecute();
然后把我们在外面调用execute("hello world")
传入的参数hello world
参数传入mWorker即要执行的任务,然后调用sDefaultExecutor
的execute
方法。之后就像上面介绍的sDefaultExecutor
先把任务加入任务队列然后串行的执行任务,任务的主要内容就是执行doInBackground
并把返回的Result
传入postResult(result);
分析到这里,我们已经可以知道doInBackground就是在THREAD_POOL_EXECUTOR线程池的子线程中执行的。
最后再来看一下postResult(result).方法:
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
//把result放到message中并发送到getHandler
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
这里可以看到,就是把result放到message中并把getHandler得到的handler作为message的target,把message的what设置成MESSAGE_POST_RESULT表示这个消息代表任务执行的结果。看一下getHandler:
private static Handler getHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler();
}
return sHandler;
}
}
getHandler只是返回了一个InternalHandler
//使用的是UI线程的Looper和消息队列
public InternalHandler() {
super(Looper.getMainLooper());
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
//what是MESSAGE_POST_RESULT,那么就处理doInbackground返回的结果
case MESSAGE_POST_RESULT:
// There is only one result
// finish内部会调用我们实现的onPostExecute方法
result.mTask.finish(result.mData[0]);
break;
//what是MESSAGE_POST_PROGRESS,那么就调用onProgressUpdate来更新progress
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
上面的注释写得很明白了,根据消息的不同,使用handler在UI线程中处理结果,或者更新progerss。
看看finish和
的代码
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
//onPostExecute就是在这里执行的
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
//publishProgress把what为MESSAGE_POST_PROGRESS的消息发送给了
// InternalHandler,所以更新了progress
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
看到这里可以总结一下,doInBackground方法是在线程池中的线程中执行,而onPreExecute是在UI线程中执行,而onPostExecute和onProgressUpdate是用过InternalHandler 从而在UI线程执行的。而且一个AsyncTask对象执行结束之后也就没用了,一个AsyncTask对象只能execute一次,否则会报异常,如果还想执行一个任务需要重新创建一个AsyncTask对象,这一点可以从executeOnExecutor的代码看出来