本文以 API 23 代码为例讲解 AsyncTask 的使用和源码以及注意事项。

AsyncTask

API 3 引入的类,目的在于简化 Android 的异步耗时操作前后的 UI 线程操作。在某种程度上来说, AsyncTask 是 ThreadHandler 的帮助类,无需关心线程调度等操作。 AsyncTask 有三个类属性,分别是 ParamsProgressResult ,和四个步骤,onPreExecutedoInBackgroundonProgressUpdateonPostExecute

使用

AsyncTask 必须得继承才能使用,子类至少得重写 doInBackground(Params...) 方法,同时也会经常重写 onPostExecute(Result) 方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}

protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}

protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}

AsyncTask 的执行很简单:

1
new DownloadFilesTask().execute(url1, url2, url3);

类属性

AsyncTask 有三个类属性,分别是:

  1. Params ,传递给 doInBackground 的参数形式
  2. Progress ,在 doInBackground 运行中计算的进度单位值(the type of the progress units published during the background computation)
  3. ResultdoInBackground 运行完成后得到的结果的形式

并不是所有的类属性都会被用到,如果有不需要的话,使用 Void

四个步骤

当 AsyncTask 被执行时,会经过四个步骤:

  1. onPreExecute() ,当执行 doInBackground 前在 UI 线程被调用
  2. doInBackground(Params...)onPreExecute() 之后在子线程中被调用。这个方法中主要处理耗时操作,最后的结构将会传递给 onPostExecute 。在这个步骤中,可以使用 publishProgress(Progess...) 来进行进度控制,当调用这个方法之后,onPregressUpdate(Progress...) 会被自动调用
  3. onPregessUpdat(Progress...) ,当调用 publishProgress(Progess...) 之后自动在 UI 线程被调用,这个方法中可以进行百分制的进度条的展示等等
  4. onPostExecute(Result) ,当 doInBackground 完成之后在 UI 线程被调用

规则

  1. 在 JELLY_BEAN 版本之前 AsyncTask 类必须在 UI 线程中加载
  2. AsyncTask 必须在 UI 线程创建
  3. execute(Params...) 方法必须在 UI 线程中调用
  4. 不要人为去调用 onPreExecute()onPostExecute(Result)doInBackground(Params...)onProgressUpdate(Progress...)
  5. task 只会被执行一次,如果调用了两次 exexute 的话将会抛出异常

源码

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
public abstract class AsyncTask<Params, Progress, Result> {

private static final int MESSAGE_POST_RESULT = 0x1;
private static final int MESSAGE_POST_PROGRESS = 0x2;

private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;

private final AtomicBoolean mCancelled = new AtomicBoolean();
private final AtomicBoolean mTaskInvoked = new AtomicBoolean();

private static InternalHandler sHandler;

/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/

public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
//mTaskInvoked是一个AtomicBoolean变量,设置为true表明task正在执行
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);
}
}
};
}

private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}

/**
* 创建一个static的Handler,这样的话所有的AsyncTask对象都是这个Handler
*/

private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}

/**
* 将Result通过Handler传递到UI线程
*/

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

/**
* 得到Handler
*/

private static Handler getHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler();
}
return sHandler;
}
}

/**
* 主线程的Handler
*/

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

/**
* 完成
*/

private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}

public final boolean isCancelled() {
return mCancelled.get();
}

/**
* Handler传递数据的时候将数据封装的形式
* mTask是为了到时将AsyncTaskResult获取到之后拿到task进行操作,比如result.mTask.onProgressUpdate(result.mData)
* mData是Result数据或者Preogress数据
*/

@SuppressWarnings({"RawUseOfParameterizedType"})
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;

AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
}

在构造方法中初始化了 mWorkermFuture 两个变量,初始化 mFuture 的时候将 mWork 作为参数传递进去了。 mWork 是一个 Callable 对象,mFuture 是一个 FutureTask 对象。

CallableFutureTask 的一般用法是让线程池去 submit 一个 Callable ,返回一个 Future 类型的变量,此时 Callable 中的操作已经添加到线程池中了,按照线程池中的调度算法进行调度运行。当返回的 Future 变量进行 get() 方法操作的时候,得到 Callable 中操作的返回值,如果操作还没有操作完,那么程序会阻塞在 get() 方法这里。

WorkerRunnablecall() 方法中调用了 doInBackground 。在 postResult 将数据通过 Handler 传递到 UI 线程,在 Handler 的 handleMessage() 中调用了 finish 方法,使 onPostExecute 被调用。

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
public abstract class AsyncTask<Params, Progress, Result> {
//我的MX5的CPU_COUNT的值为8  
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
//那么这里为9,同一时刻能够运行的线程数为9个  
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
//那么这里为17,即线程池大小为17  
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
//每次只能执行1个
private static final int KEEP_ALIVE = 1;

/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/

public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

/**
* An {@link Executor} that executes tasks one at a time in serial
* order. This serialization is global to a particular process.
* 串行池,UI线程,对应之前讲到的 AsyncTask 类必须在 UI 线程中加载
*/

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

private static class SerialExecutor implements Executor {
//队列
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
//当前执行的Runnable      
Runnable mActive;

public synchronized void execute(final Runnable r) {
//向队列中添加runnable,new一个Runnable出来,执行传递进来的runnable.run,无论传递进来的runnable发生什么事,继续执行下一个runnable
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}

protected synchronized void scheduleNext() {
//出队列,将值传递给mActive  
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}

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

@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) {
//这里就是之前介绍说到的,一个task只能被执行一次
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)");
}
}
//将状态改为RUNNING
mStatus = Status.RUNNING;
//调用onPreExecute
onPreExecute();
//将参数传递给mWorker
mWorker.mParams = params;
//执行
exec.execute(mFuture);

return this;
}

/**
* Indicates the current status of the task. Each status will be set only once
* during the lifetime of a task.
*/

public enum Status {
/**
* Indicates that the task has not been executed yet.
* 表示task还没有被执行
*/

PENDING,
/**
* Indicates that the task is running.
* 表示task正在运行
*/

RUNNING,
/**
* Indicates that {@link AsyncTask#onPostExecute} has finished.
* 表示task已经运行完了
*/

FINISHED,
}
}

在执行 execute 方法的时候就会调用 onPreExecute

SERIAL_EXECUTOR 说明了之前的 规则 1executeOnExecutor 说明了之前的 规则 5

publishProgress

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
public abstract class AsyncTask<Params, Progress, Result> {
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}

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

通过调用 publishProgress 方法,将数据通过 Handler 传递到 UI 线程,在 handleMessage() 中处理,调用了 onProgressUpdate

其他的方法

使用自定义的线程池

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
public abstract class AsyncTask<Params, Progress, Result> {
@MainThread
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 该方法之前分析过,但是需要注意的是该方法是 public ,所以用户可以传入自己的线程池。

1
2
Executor exec = new ThreadPoolExecutor(15, 200, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());  
new DownloadTask().executeOnExecutor(exec);

但是比较麻烦的是每次都需要这么写,有没有简单点的方法呢,是有的:

1
2
3
4
5
6
public abstract class AsyncTask<Params, Progress, Result> {
/** @hide */
public static void setDefaultExecutor(Executor exec) {
sDefaultExecutor = exec;
}
}

该方法是被隐藏了的,但是可以通过反射调用。

Cancel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public abstract class AsyncTask<Params, Progress, Result> {
private final AtomicBoolean mCancelled = new AtomicBoolean();

public final boolean cancel(boolean mayInterruptIfRunning) {
mCancelled.set(true);
return mFuture.cancel(mayInterruptIfRunning);
}

public final boolean isCancelled() {
return mCancelled.get();
}

@MainThread
protected void onCancelled() {
}

@SuppressWarnings({"UnusedParameters"})
@MainThread
protected void onCancelled(Result result) {
onCancelled();
}
}

AsyncTask 的取消操作是封装好的,只需要调用就行。

get

1
2
3
4
5
6
7
8
9
public abstract class AsyncTask<Params, Progress, Result> {
public final Result get() throws InterruptedException, ExecutionException {
return mFuture.get();
}

public final Result get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return mFuture.get(timeout, unit);
}
}

也可以直接通过 get() 方法拿到最后的值,只不过没拿到值前会阻塞线程。

AsyncTaskCompat

support V4 中有一个 AsyncTask 的兼容类 AsyncTaskCompat 。主要逻辑就是在 API 11 之前并行处理 Task,而 API 11 之后也改为并行处理 Task 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class AsyncTaskCompat {
public static <Params, Progress, Result> AsyncTask<Params, Progress, Result> executeParallel(
AsyncTask<Params, Progress, Result> task,
Params... params) {
if (task == null) {
throw new IllegalArgumentException("task can not be null");
}

if (Build.VERSION.SDK_INT >= 11) {
// From API 11 onwards, we need to manually select the THREAD_POOL_EXECUTOR
AsyncTaskCompatHoneycomb.executeParallel(task, params);
} else {
// Before API 11, all tasks were run in parallel
task.execute(params);
}

return task;
}
}

总结

  • AsyncTask 只能执行一次
  • 尽量在 UI 线程加载和创建 AsyncTask
  • 并行操作的话可以通过 AsyncTaskCompat 或者 executeOnExecutor(exec) 来实现
  • 如果 cancel 掉 Task 的话,会调用 onCancel()