关于AsyncTask的使用可以参看android sdk提供的AsyncTask相关文档,本文来解析AsyncTask的源代码。
我们只需要调用AsyncTask的execute方法,因此我们也将从这里开始。
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
if (mStatus != Status.PENDING) {//Status有PENDING(未执行),RUNNING(正在执行),FINISHED(已完成)三个状态,如果mStatus不为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;//从PENDING状态转为RUNNING,所以当AsyncTask只能调用一次execute,第二次调用时mStatus为RUNNING就会抛出异常
onPreExecute();//由UI线程在执行doInBackground方法之前执行
mWorker.mParams = params;//mWorker为WorkerRunnable类型,WorkerRunnable是AsyncTask的一个抽象静态内部类,该类继承了Callable接口,并且拥有Params[] mParams做为其成员
sExecutor.execute(mFuture);//mFuture为FutureTask类型,该类实现Future<V>, Runnable接口,sExecutor是一个ThreadPoolExecutor类型
return this;
}
当执行sExecutor.execute(mFuture)时,调用了ThreadPoolExecutor中的execute方法,该方法使用一个Runnable作为参数,如下:
public void execute(Runnable command) {
......
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
......
}
其中addWorker方法会把传进来的Runnable对象放入其工作队列中,并执行该Runnable,如下:
private boolean addWorker(Runnable firstTask, boolean core) {
.....
Worker w = new Worker(firstTask);
Thread t = w.thread;
final ReentrantLock mainLock = this.mainLock;//获得线程锁
mainLock.lock();//锁住线程
try {
int c = ctl.get();
int rs = runStateOf(c);
if (t == null ||
(rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null))) {
decrementWorkerCount();
tryTerminate();
return false;
}
workers.add(w);//放入工作队列
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
} finally {
mainLock.unlock();//开锁
}
t.start();//执行线程,关键
...
return true;
}
到此我们知道AsyncTask的execute的执行流程为
先调用ThreadPoolExecutor.execute(mFuture);
然后ThreadPoolExecutor.execute(mFuture) 会调用ThreadPoolExecutor.addWorker(mFuture);
最后ThreadPoolExecutor.addWorker(mFuture)会调用mFuture的run()方法,run方法中就是该线程要执行操作的地方
到此我们来关注一下mFuture,AsyncTask中的mFuture是一个FutureTask,FutureTask实现了Future<V>, Runnable两个接口,
Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果,计算完成后只能使用 get 方法来获取结果。
mFuture以mWorker作为参数
mFuture = new FutureTask<Result>(mWorker) {
。。。。
}
用到了FutureTask的一个构造函数
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
sync = new Sync(callable);
}
sync为Sync类,Sync类为FutureTask的内部类,该类是AbstractQueuedSynchronizer类的子类
private final class Sync extends AbstractQueuedSynchronizer{
...
}
因此我们知道mWorker是一个实现了callable接口的类,并且持有Params[] mParams参数
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
我们再来看看FutureTask的run方法
public void run() {
sync.innerRun();
}
调用了sync的innerRun()方法。
void innerRun() {
...
runner = Thread.currentThread();
if (getState() == RUNNING) { // recheck after setting thread
V result;
try {
result = callable.call();//调用callable的call方法并返回值,此时的callable为mWorker
} catch (Throwable ex) {
setException(ex);
return;
}
set(result);//设置结果
} else {
releaseShared(0); // cancel
}
}
innerRun方法中调用了callable的call方法,该callable在这里就是mWorker,我们来看看mWorker的call方法
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return doInBackground(mParams);
}
};
先设置线程级别为THREAD_PRIORITY_BACKGROUND(10),Linux线程级别从-20(最高)~19(最低),普通级别值为0,因而THREAD_PRIORITY_BACKGROUND级别比普通级别低
然后执行AsyncTask的doInBackground方法,并返回结果。所以当我们把耗时的工作量放在doInBackground方法里执行时,实际上是把大工作量放到了一个低级别的线程中去执行。
FutureTask中的run方法调用完callable.call()并获得结果之后就会调用set(result)方法,我们来看看set方法
protected void set(V v) {
sync.innerSet(v);
}
调用sync的innerSet方法:
void innerSet(V v) {
for (;;) {
...
if (compareAndSetState(s, RAN)) {
result = v;
releaseShared(0);
done();//调用了FutureTask的done();方法
return;
}
}
}
innerSet中又调用了mFuture的done方法,我们来看看done方法
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
Message message;
Result result = null;
try {
result = get();//调用FutureTask的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) {
message = sHandler.obtainMessage(MESSAGE_POST_CANCEL,
new AsyncTaskResult<Result>(AsyncTask.this, (Result[]) null));//取消任务,由sHandler去处理
message.sendToTarget();
return;
} catch (Throwable t) {
throw new RuntimeException("An error occured while executing "
+ "doInBackground()", t);
}
message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(AsyncTask.this, result));
message.sendToTarget();
}
};
FutureTask的get()方法会等待线程的执行结果,在等待的过程中用户可能会执行mFuture的cancel方法来取消任务
public final boolean cancel(boolean mayInterruptIfRunning) {
return mFuture.cancel(mayInterruptIfRunning);
}
此时done()中get()会抛出CancellationException异常,捕获取消任务异常,转由sHandler去处理异常,
...
} catch (CancellationException e) {
message = sHandler.obtainMessage(MESSAGE_POST_CANCEL,
new AsyncTaskResult<Result>(AsyncTask.this, (Result[]) null));//取消任务,由sHandler去处理
message.sendToTarget();
return;
}
...
而get()顺利获取到结果时也转由sHandler来处理
...
message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(AsyncTask.this, result));
message.sendToTarget();
...
我们来看看sHandler,sHandler为InternalHandler,该类是AsyncTask的内部类
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;
case MESSAGE_POST_CANCEL:
result.mTask.onCancelled();
break;
}
}
}
该handler的handleMessage集中来处理任务执行的完成情况
1、MESSAGE_POST_RESULT,成功执行完任务时,调用AsyncTask的finish(result)方法,参数为返回的结果
AsyncTask的finish(result)方法:
private void finish(Result result) {
if (isCancelled()) result = null;
onPostExecute(result);
mStatus = Status.FINISHED;
}
调用了onPostExecute(result)方法,并把状态改正已执行结束。
因而AsyncTask的onPostExecute方法一般是在执行doInBackground方法之后由UI线程来执行收尾工作,
2、MESSAGE_POST_PROGRESS 执行AsyncTask的onProgressUpdate方法,一般用来在任务执行中进行进度条的更新等,该MESSAGE_POST_PROGRESS是由publishProgress方法的调用来引起的
protected final void publishProgress(Progress... values) {
sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
而publishProgress方法一般是在doInBackground中根据实际情况来更新UI线程,比如更新进度条等。
1、MESSAGE_POST_CANCEL,取消任务,调用了AsyncTask的.onCancelled()方法
其中onPostExecute、publishProgress、onCancelled都是由子类提供的。
到这里AsyncTask类的使用也就很简单了,
AsyncTask的执行分为四个步骤,每一步都对应一个回调方法,这些方法不应该由应用程序调用,开发者需要做的就是实现这些方法。
onPreExecute(), 该方法将在执行实际的后台操作前被UI thread调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。
doInBackground(Params...), 将在onPreExecute 方法执行后马上执行,该方法运行在后台线程中。这里将主要负责执行那些很耗时的后台计算工作。可以调用 publishProgress方法来更新实时的任务进度。该方法是抽象方法,子类必须实现。
onProgressUpdate(Progress...),在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。
onPostExecute(Result), 在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用,后台的计算结果将通过该方法传递到UI thread.
AsyncTask的调用也很简单,只要在UI线程中执行execute方法
为了正确的使用AsyncTask类,以下是几条必须遵守的准则:
1) Task的实例必须在UI thread中创建
2) execute方法必须在UI thread中调用
3) 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法
4) 该task只能被执行一次,否则多次调用时将会出现异常
doInBackground方法和onPostExecute的参数必须对应,这两个参数在AsyncTask声明的泛型参数列表中指定,第一个为 doInBackground接受的参数,第二个为显示进度的参数,第第三个为doInBackground返回和onPostExecute传入的参数。