Android之AsyncTask

Activity 之 AsyncTask

引入

Android UI 是线程不安全的,子线程要进行 UI 操作,需要借助 Android 的异步消息处理机制。使用 AsyncTask(1.5 引入)可以方便地从子线程切换到 UI 线程。

基本用法

三个泛型参数:
Params: 在执行 AsyncTask 时需要传入的参数,可用于在后台任务中使用。
Progress:后台任务执行时,如果需要在界面上显示当前进度,则使用这里指定的泛型作为进度单位。
Result:当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class DownloadTask extends AsyncTask<Void, Integer, Boolean>{
@Override
protected void onPreExecute(){
//可早这里进行一些初始化操作
}

@Override
protected Boolean doInBackground(Void... params){
//子线程处理后台任务,返回执行结果,这里是 Boolean
publishProgress(downloadPercent);// 从子线程切换到 UI 线程
}

@Override
protected void onProgressUpdate(Integer... values){
//方法中携带的参数就是在后台任务中传递过来的
}

@Override
protected void onPostExecute(Boolean result){
//后台任务执行完毕,利用返回数据可进行一些 UI 操作
}
}

new DownloadTask().execute();

分析 AsyncTask 源码

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
public AsyncTask(){
mWorker = new WorkerRunnable<Params, Result>(){
public Result call() throws Exception {
mTaskInvoked.set(true);

Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return postResult(doInBackground(mParams));
}
};

mFuture = new FutureTask<Result>(mWorker){
@Override
protected void done(){
try{
final Result result = get();
postResultIfNotInvoked(result);
}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);
}catch (Throwabl t) {
throw new RuntimeException("An error occured while executing doInBackground()", t);
}
}
}
}

mWorker 是一个 Callable 对象, mFuture 是一个 FutureTask 对象,这两个变量暂时保存在内存中,稍后才会用到它们。

调用execute():

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

execute()->executeOnExecutor()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public final AsyncTask<Params, Process, Result> executeOnExecutor(Exceutor 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()->onPreExecute()->exec.execute(mFuture)
exec:sDefaultExecutor:

1
2
3
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
...
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

execute()->executeOnExecutor()->onPreExecute()->exec.execute(mFuture)SerialExecutor.execute()
刚才在executeOnExecutor()中调用execute(),其实也就是调用 SerialExecutor 类中的 execute();

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
private static class SerialExecutor implements Executor{
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;

public synchronized void execute(final Runnable r){
// r 也即是 mFuture 对象
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){
THRED_POOL_EXECUTOR.execute(mActive);
}
}
}

execute()->executeOnExecutor()->onPreExecute()->exec.execute(mFuture)SerialExecutor.execute()->mFuture.run()->Sync.innerRun()
Sync 为 SerialExecutor 的内部类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void innerRun(){
if(!compareAndSetState(READY, RUNNING))
return ;
runner = Thread.currentThread();
if(getState() == RUNNING){ // recheck after setting thread
V result;
try {
// 初始化 mFuture 对象时传入的 mWorker 对象
result = callable.call();
} catch(Throwable ex) {
setException(ex);
return;
}
set(result);
}else{
releaseShared(0); // cancel
}
}

execute()->executeOnExecutor()->onPreExecute()->exec.execute(mFuture)SerialExecutor.execute()->mFuture.run()->Sync.innerRun()->mWorker.call()->postResult()

1
2
3
4
5
private Result postResult(Result result){
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}

sHandler 对象是 InternalHandler 类的一个实例,稍后message.sendToTarget()的消息会在 InternalHandler 的handleMessage()中被处理。

execute()->executeOnExecutor()->onPreExecute()->exec.execute(mFuture)SerialExecutor.execute()->mFuture.run()->Sync.innerRun()->mWorker.call()->postResult()->InternalHandler.handleMessage()

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

这里对消息的类型进行了判断,MESSAGE_POST_RESULT 就会去执行finish();MESSAGE_POST_PROGRESS 就会去执行onProgressUpdate()finish()方法:

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

我们注意到,在 InternalHandler 中的handleMessage()中,MESSAGE_POST_PROGRESS 消息类型是用于显示当前进度的,调用的正是onProgressUpdate(),publishProgress()就会发出 MESSAGE_POST_PROGRESS 这样一条信息。

1
2
3
4
5
protected final void publishProgress(Progress... values){
if(!isCancelled()){
sHandler.obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}

AsyncTask 使用的是也是异步消息处理机制,只是做了非常好的封装而已

关于 SerialExecutor

SerialExecutor 是使用 ArrayDeque 这个队列来管理 Runnable 对象的,如果我们一次启动了很多个任务,首先在第一次运行execute()方法的时候,会调用 ArrayDeque 的offer()方法将传入的 Runnable 对象添加到队列的尾部,然后判断 mActive 对象是不是等于 null,第一次运行当然是等于 null 了,于是会调用scheduleNext()。在这个方法中会从队列头部取值,并赋值给 mActive 对象,然后调用 THREAD_POOL_EXECUTOR 去执行取出的 Runnable 对象。之后如何又有新的任务被执行,同样还是会调用offer()方法将传入的 Runnable 对象添加到队列的尾部,但再去给 mActive 对象做非空检查的时候就会发现 mActive 对象已经不再是 null 了,于是就不会再调用scheduleNext()。其中的 try finally 代码块保证了scheduleNext()一定会被调用。也就是说,每当一个任务执行完毕后,下一个任务才会得到执行,SerialExecutor 模仿的是单一线程的结果。如果我们快速地启动了很多任务,同一时刻只会有一个线程正在执行,其余为等待状态。

在 3.0 之前的 AsyncTask 可以同时又5个任务执行,而之后默认只能有1个任务在执行。升级之后,当然我们可以灵活自由地配置:

1
2
3
//允许同时 15 个任务正在执行
Executor exec = new ThreadPoolExecutor(15, 200, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
new DownloadTask().executeOnExecutor(exec);


参考引用

Android AsyncTask完全解析,带你从源码的角度彻底理解