AsyncTask解析

Posted by alonealice on 2016-07-23

AsyncTask是我们在开发过程中经常使用的类,它是一个抽象类,主要用来实现轻量级异步操作。那接下来我们就看看它的内部实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);

Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(result);
}
};

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);
}
}
};
}

AsyncTask的构造方法主要实现了初始化了两个对象,一个是WorkerRunnable对象mWorker,WorkerRunnable是它的内部静态类,并且实现了Callable接口,里面只有一个数组;另一个是FutureTask对象mFuture,该类实现了Runnable接口和Futrue接口。这两个对象具体有什么用,先按下不表。
使用AsyncTask时,我们都需要调用excute方法,并且传入相应的参数,那就来看看excute的实现。

1
2
3
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}

这里它调用了executeOnExecutor方法,同时传入sDefaultExecutor和我们外边传入的参数。sDefaultExecutor是一个线程池,它的用处后面再说。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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;
}

executeOnExecutor方法中,首先是判断整个任务的状态,只有当任务状态为等待时才能执行,同时我们也可以发现,整个类中没有将状态重新置为等待的方法,所以说明一个AsyncTask对象只能执行一次。之后会执行onPreExecute方法,进行任务前的预操作,同时将传入的参数胡设置到mWorker中,然后将FutureTask对象mFuture添加到线程池中执行。接下来就看一下这个sDefaultExecutor线程池的实现。
sDefaultExecutor是AsyncTask的静态类SerialExecutor对象,它实现了Executor接口,里面有一个任务队列和一个当前任务对象,在它的execute方法中,我们可以发现,它并没有去实现具体的操作逻辑,只是将添加的任务添加到任务队列中,同时当当前任务对象为空时,从队列中取出任务,在THREAD_POOL_EXECUTOR线程池中执行。THREAD_POOL_EXECUTOR是AsyncTask的静态对象,这样做可以减少线程池的创建。同时它的核心线程数为cpu+1个,最大线程数为cpu*2+1个,线程存活时间为1s,任务队列空间为128。该线程最终会执行添加进来的mFuture任务。
那接来下看一下mFuture的实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}

之前说过,FutureTask实现了runnable接口,在其run方法中,我们发现它会去调用在创建时传入的Callable对象的call方法,获得返回值后,调用set方法设置返回值,最后调用外AsyncTask中实现的done方法。
call方法实现如下:

1
2
3
4
5
6
7
8
9
10
11
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);

Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(result);
}
};

call方法中主要是执行doInBackground方法,获得返回值后返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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);
}
}
};

而done方法这时获取之前的结果,并且调用postResultIfNotInvoked方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}

private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}

postResultIfNotInvoked方法中最终会将之前的结果打包成一个message到hanlder。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}

@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创建在主线程中,处理主要分两种,一种是更新进度,一种是结束事件。

1
2
3
4
5
6
7
8
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}

结束事件时会调用finish方法,最终会执行自己实现的onPostExecute方法,而更新进度时则会执行实现的onProgressUpdate方法。
最后总结一下,AsyncTask使用时,会有一个线程池,用来执行具体的任务,还有一个Executor,用来添加、获取任务。同时在执行任务时,会有一个Callable处理多线程任务,同时回调结果,结果回调到runnable接口,同时使用handler执行主线程回调方法。