前言
什么是AsyncTask,相信搞过android开发的朋友们都不陌生。AsyncTask内部封装了Thread和Handler,可以让我们在后台进行计算并且把计算的结果及时更新到UI上,而这些正是Thread+Handler所做的事情,没错,AsyncTask的作用就是简化Thread+Handler,让我们能够通过更少的代码来完成一样的功能,这里,我要说明的是:AsyncTask只是简化Thread+Handler而不是替代,实际上它也替代不了。同时,AsyncTask从最开始到现在已经经过了几次代码修改,任务的执行逻辑慢慢地发生了改变,并不是大家所想象的那样:AsyncTask是完全并行执行的就像多个线程一样,其实不是的,所以用AsyncTask的时候还是要注意,下面会一一说明。另外本文主要是分析AsyncTask的源代码以及使用时候的一些注意事项,如果你还不熟悉AsyncTask,请先阅读android之AsyncTask 来了解其基本用法。
这里先给出AsyncTask的一个例子:
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的规则
- AsyncTask的类必须在UI线程加载(从4.1开始系统会帮我们自动完成)
- AsyncTask对象必须在UI线程创建
- execute方法必须在UI线程调用
- 不要在你的程序中去直接调用onPreExecute(), onPostExecute, doInBackground, onProgressUpdate方法
- 一个AsyncTask对象只能执行一次,即只能调用一次execute方法,否则会报运行时异常
- AsyncTask不是被设计为处理耗时操作的,耗时上限为几秒钟,如果要做长耗时操作,强烈建议你使用Executor,ThreadPoolExecutor以及FutureTask
- 在1.6之前,AsyncTask是串行执行任务的,1.6的时候AsyncTask开始采用线程池里处理并行任务,但是从3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask又采用一个线程来串行执行任务
AsyncTask到底是串行还是并行?
给大家做一下实验,请看如下实验代码:代码很简单,就是点击按钮的时候同时执行5个AsyncTask,每个AsyncTask休眠3s,同时把每个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
|
@Override
public
void
onClick
(
View
v
)
{
if
(
v
==
mButton
)
{
new
MyAsyncTask
(
"AsyncTask#1"
)
.
execute
(
""
)
;
new
MyAsyncTask
(
"AsyncTask#2"
)
.
execute
(
""
)
;
new
MyAsyncTask
(
"AsyncTask#3"
)
.
execute
(
""
)
;
new
MyAsyncTask
(
"AsyncTask#4"
)
.
execute
(
""
)
;
new
MyAsyncTask
(
"AsyncTask#5"
)
.
execute
(
""
)
;
}
}
private
static
class
MyAsyncTask
extends
AsyncTask
<
String
,
Integer
,
String
>
{
private
String
mName
=
"AsyncTask"
;
public
MyAsyncTask
(
String
name
)
{
super
(
)
;
mName
=
name
;
}
@Override
protected
String
doInBackground
(
String
.
.
.
params
)
{
try
{
Thread
.
sleep
(
3000
)
;
}
catch
(
InterruptedException
e
)
{
e
.
printStackTrace
(
)
;
}
return
mName
;
}
@Override
protected
void
onPostExecute
(
String
result
)
{
super
.
onPostExecute
(
result
)
;
SimpleDateFormat
df
=
new
SimpleDateFormat
(
"yyyy-MM-dd HH:mm:ss"
)
;
Log
.
e
(
TAG
,
result
+
"execute finish at "
+
df
.
format
(
new
Date
(
)
)
)
;
}
}
|
我找了2个手机,系统分别是4.1.1和2.3.3,按照我前面的描述,AsyncTask在4.1.1应该是串行的,在2.3.3应该是并行的,到底是不是这样呢?请看Log
Android 4.1.1上执行:从下面Log可以看出,5个AsyncTask共耗时15s且时间间隔为3s,很显然是串行执行的
Android 2.3.3上执行:从下面Log可以看出,5个AsyncTask的结束时间是一样的,很显然是并行执行
结论:从上面的两个Log可以看出,我前面的描述是完全正确的。下面请看源码,让我们去了解下其中的原理。
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
|
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
android
.
os
;
import
java
.
util
.
ArrayDeque
;
import
java
.
util
.
concurrent
.
BlockingQueue
;
import
java
.
util
.
concurrent
.
Callable
;
import
java
.
util
.
concurrent
.
CancellationException
;
import
java
.
util
.
concurrent
.
Executor
;
import
java
.
util
.
concurrent
.
ExecutionException
;
import
java
.
util
.
concurrent
.
FutureTask
;
import
java
.
util
.
concurrent
.
LinkedBlockingQueue
;
import
java
.
util
.
concurrent
.
ThreadFactory
;
import
java
.
util
.
concurrent
.
ThreadPoolExecutor
;
import
java
.
util
.
concurrent
.
TimeUnit
;
import
java
.
util
.
concurrent
.
TimeoutException
;
import
java
.
util
.
concurrent
.
atomic
.
AtomicBoolean
;
import
java
.
util
.
concurrent
.
atomic
.
AtomicInteger
;
public
abstract
class
AsyncTask
<
Params
,
Progress
,
Result
>
{
private
static
final
String
LOG_TAG
=
"AsyncTask"
;
//获取当前的cpu核心数
private
static
final
int
CPU_COUNT
=
Runtime
.
getRuntime
(
)
.
availableProcessors
(
)
;
//线程池核心容量
private
static
final
int
CORE_POOL_SIZE
=
CPU_COUNT
+
1
;
//线程池最大容量
private
static
final
int
MAXIMUM_POOL_SIZE
=
CPU_COUNT
*
2
+
1
;
//过剩的空闲线程的存活时间
private
static
final
int
KEEP_ALIVE
=
1
;
//ThreadFactory 线程工厂,通过工厂方法newThread来获取新线程
private
static
final
ThreadFactory
sThreadFactory
=
new
ThreadFactory
(
)
{
//原子整数,可以在超高并发下正常工作
private
final
AtomicInteger
mCount
=
new
AtomicInteger
(
1
)
;
public
Thread
newThread
(
Runnable
r
)
{
return
new
Thread
(
r
,
"AsyncTask #"
+
mCount
.
getAndIncrement
(
)
)
;
}
}
;
//静态阻塞式队列,用来存放待执行的任务,初始容量:128个
private
static
final
BlockingQueue
<Runnable>
sPoolWorkQueue
=
new
LinkedBlockingQueue
<Runnable>
(
128
)
;
/**
* 静态并发线程池,可以用来并行执行任务,尽管从3.0开始,AsyncTask默认是串行执行任务
* 但是我们仍然能构造出并行的AsyncTask
*/
public
static
final
Executor
THREAD_POOL_EXECUTOR
=
new
ThreadPoolExecutor
(
CORE_POOL_SIZE
,
MAXIMUM_POOL_SIZE
,
KEEP_ALIVE
,
TimeUnit
.
SECONDS
,
sPoolWorkQueue
,
sThreadFactory
)
;
/**
* 静态串行任务执行器,其内部实现了串行控制,
* 循环的取出一个个任务交给上述的并发线程池去执行
*/
public
static
final
Executor
SERIAL_EXECUTOR
=
new
SerialExecutor
(
)
;
//消息类型:发送结果
private
static
final
int
MESSAGE_POST_RESULT
=
0x1
;
//消息类型:更新进度
private
static
final
int
MESSAGE_POST_PROGRESS
=
0x2
;
/**静态Handler,用来发送上述两种通知,采用UI线程的Looper来处理消息
* 这就是为什么AsyncTask必须在UI线程调用,因为子线程
* 默认没有Looper无法创建下面的Handler,程序会直接Crash
*/
private
static
final
InternalHandler
sHandler
=
new
InternalHandler
(
)
;
//默认任务执行器,被赋值为串行任务执行器,就是它,AsyncTask变成串行的了
private
static
volatile
Executor
sDefaultExecutor
=
SERIAL_EXECUTOR
;
//如下两个变量我们先不要深究,不影响我们对整体逻辑的理解
private
final
WorkerRunnable
<
Params
,
Result
>
mWorker
;
private
final
FutureTask
<Result>
mFuture
;
//任务的状态 默认为挂起,即等待执行,其类型标识为易变的(volatile)
private
volatile
Status
mStatus
=
Status
.
PENDING
;
//原子布尔型,支持高并发访问,标识任务是否被取消
private
final
AtomicBoolean
mCancelled
=
new
AtomicBoolean
(
)
;
//原子布尔型,支持高并发访问,标识任务是否被执行过
private
final
AtomicBoolean
mTaskInvoked
=
new
AtomicBoolean
(
)
;
/*串行执行器的实现,我们要好好看看,它是怎么把并行转为串行的
*目前我们需要知道,asyncTask.execute(Params ...)实际上会调用
*SerialExecutor的execute方法,这一点后面再说明。也就是说:当你的asyncTask执行的时候,
*首先你的task会被加入到任务队列,然后排队,一个个执行
*/
private
static
class
SerialExecutor
implements
Executor
{
//线性双向队列,用来存储所有的AsyncTask任务
final
ArrayDeque
<Runnable>
mTasks
=
new
ArrayDeque
<Runnable>
(
)
;
//当前正在执行的AsyncTask任务
Runnable
mActive
;
public
synchronized
void
execute
(
final
Runnable
r
)
{
//将新的AsyncTask任务加入到双向队列中
mTasks
.
offer
(
new
Runnable
(
)
{
public
void
run
(
)
{
try
{
//执行AsyncTask任务
r
.
run
(
)
;
}
finally
{
//当前AsyncTask任务执行完毕后,进行下一轮执行,如果还有未执行任务的话
//这一点很明显体现了AsyncTask是串行执行任务的,总是一个任务执行完毕才会执行下一个任务
scheduleNext
(
)
;
}
}
}
)
;
//如果当前没有任务在执行,直接进入执行逻辑
if
(
mActive
==
null
)
{
scheduleNext
(
)
;
}
}
protected
synchronized
void
scheduleNext
(
)
{
//从任务队列中取出队列头部的任务,如果有就交给并发线程池去执行
if
(
(
mActive
=
mTasks
.
poll
(
)
)
!=
null
)
{
THREAD_POOL_EXECUTOR
.
execute
(
mActive
)
;
}
}
}
/**
* 任务的三种状态
*/
public
enum
Status
{
/**
* 任务等待执行
*/
PENDING
,
/**
* 任务正在执行
*/
RUNNING
,
/**
* 任务已经执行结束
*/
FINISHED
,
}
/** 隐藏API:在UI线程中调用,用来初始化Handler */
public
static
void
init
(
)
{
sHandler
.
getLooper
(
)
;
}
/** 隐藏API:为AsyncTask设置默认执行器 */
public
static
void
setDefaultExecutor
(
Executor
exec
)
{
sDefaultExecutor
=
exec
;
}
/**
* 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
.
set
(
true
)
;
Process
.
setThreadPriority
(
Process
.
THREAD_PRIORITY_BACKGROUND
)
;
//noinspection unchecked
return
postResult
(
doInBackground
(
mParams
)
)
;
}
}
;
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 occured while executing doInBackground()"
,
e
.
getCause
(
)
)
;
}
catch
(
CancellationException
e
)
{
postResultIfNotInvoked
(
null
)
;
}
}
}
;
}
private
void
postResultIfNotInvoked
(
Result
result
)
{
final
boolean
wasTaskInvoked
=
mTaskInvoked
.
get
(
)
;
if
(
!
wasTaskInvoked
)
{
postResult
(
result
)
;
}
}
//doInBackground执行完毕,发送消息
private
Result
postResult
(
Result
result
)
{
@SuppressWarnings
(
"unchecked"
)
Message
message
=
sHandler
.
obtainMessage
(
MESSAGE_POST_RESULT
,
new
AsyncTaskResult
<Result>
(
this
,
result
)
)
;
message
.
sendToTarget
(
)
;
return
result
;
}
/**
* 返回任务的状态
*/
public
final
Status
getStatus
(
)
{
return
mStatus
;
}
/**
* 这个方法是我们必须要重写的,用来做后台计算
* 所在线程:后台线程
*/
protected
abstract
Result
doInBackground
(
Params
.
.
.
params
)
;
/**
* 在doInBackground之前调用,用来做初始化工作
* 所在线程:UI线程
*/
protected
void
onPreExecute
(
)
{
}
/**
* 在doInBackground之后调用,用来接受后台计算结果更新UI
* 所在线程:UI线程
*/
protected
void
onPostExecute
(
Result
result
)
{
}
/**
* Runs on the UI thread after {@link #publishProgress} is invoked.
/**
* 在publishProgress之后调用,用来更新计算进度
* 所在线程:UI线程
*/
protected
void
onProgressUpdate
(
Progress
.
.
.
values
)
{
}
/**
* cancel被调用并且doInBackground执行结束,会调用onCancelled,表示任务被取消
* 这个时候onPostExecute不会再被调用,二者是互斥的,分别表示任务取消和任务执行完成
* 所在线程:UI线程
*/
@SuppressWarnings
(
{
"UnusedParameters"
}
)
protected
void
onCancelled
(
Result
result
)
{
onCancelled
(
)
;
}
protected
void
onCancelled
(
)
{
}
public
final
boolean
isCancelled
(
)
{
return
mCancelled
.
get
(
)
;
}
public
final
boolean
cancel
(
boolean
mayInterruptIfRunning
)
{
mCancelled
.
set
(
true
)
;
return
mFuture
.
cancel
(
mayInterruptIfRunning
)
;
}
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
)
;
}
/**
* 这个方法如何执行和系统版本有关,在AsyncTask的使用规则里已经说明,如果你真的想使用并行AsyncTask,
* 也是可以的,只要稍作修改
* 必须在UI线程调用此方法
*/
public
final
AsyncTask
<
Params
,
Progress
,
Result
>
execute
(
Params
.
.
.
params
)
{
//串行执行
return
executeOnExecutor
(
sDefaultExecutor
,
params
)
;
//如果我们想并行执行,这样改就行了,当然这个方法我们没法改
//return executeOnExecutor(THREAD_POOL_EXECUTOR, params);
}
/**
* 通过这个方法我们可以自定义AsyncTask的执行方式,串行or并行,甚至可以采用自己的Executor
* 为了实现并行,我们可以在外部这么用AsyncTask:
* asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Params... params);
* 必须在UI线程调用此方法
*/
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
.
mParams
=
params
;
//然后后台计算#doInBackground才真正开始
exec
.
execute
(
mFuture
)
;
//接着会有#onProgressUpdate被调用,最后是#onPostExecute
return
this
;
}
/**
* 这是AsyncTask提供的一个静态方法,方便我们直接执行一个runnable
*/
public
static
void
execute
(
Runnable
runnable
)
{
sDefaultExecutor
.
execute
(
runnable
)
;
}
/**
* 打印后台计算进度,onProgressUpdate会被调用
*/
protected
final
void
publishProgress
(
Progress
.
.
.
values
)
{
if
(
!
isCancelled
(
)
)
{
sHandler
.
obtainMessage
(
MESSAGE_POST_PROGRESS
,
new
AsyncTaskResult
<Progress>
(
this
,
values
)
)
.
sendToTarget
(
)
;
}
}
//任务结束的时候会进行判断,如果任务没有被取消,则onPostExecute会被调用
private
void
finish
(
Result
result
)
{
if
(
isCancelled
(
)
)
{
onCancelled
(
result
)
;
}
else
{
onPostExecute
(
result
)
;
}
mStatus
=
Status
.
FINISHED
;
}
//AsyncTask内部Handler,用来发送后台计算进度更新消息和计算完成消息
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
;
}
}
}
private
static
abstract
class
WorkerRunnable
<
Params
,
Result
>
implements
Callable
<Result>
{
Params
[
]
mParams
;
}
@SuppressWarnings
(
{
"RawUseOfParameterizedType"
}
)
private
static
class
AsyncTaskResult
<Data>
{
final
AsyncTask
mTask
;
final
Data
[
]
mData
;
AsyncTaskResult
(
AsyncTask
task
,
Data
.
.
.
data
)
{
mTask
=
task
;
mData
=
data
;
}
}
}
|
让你的AsyncTask在3.0以上的系统中并行起来
通过上面的源码分析,我已经给出了在3.0以上系统中让AsyncTask并行执行的方法,现在,让我们来试一试,代码还是之前采用的测试代码,我们要稍作修改,调用AsyncTask的executeOnExecutor方法而不是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
|
@TargetApi
(
Build
.
VERSION_CODES
.
HONEYCOMB
)
@Override
public
void
onClick
(
View
v
)
{
if
(
v
==
mButton
)
{
new
MyAsyncTask
(
"AsyncTask#1"
)
.
executeOnExecutor
(
AsyncTask
.
THREAD_POOL_EXECUTOR
,
""
)
;
new
MyAsyncTask
(
"AsyncTask#2"
)
.
executeOnExecutor
(
AsyncTask
.
THREAD_POOL_EXECUTOR
,
""
)
;
new
MyAsyncTask
(
"AsyncTask#3"
)
.
executeOnExecutor
(
AsyncTask
.
THREAD_POOL_EXECUTOR
,
""
)
;
new
MyAsyncTask
(
"AsyncTask#4"
)
.
executeOnExecutor
(
AsyncTask
.
THREAD_POOL_EXECUTOR
,
""
)
;
new
MyAsyncTask
(
"AsyncTask#5"
)
.
executeOnExecutor
(
AsyncTask
.
THREAD_POOL_EXECUTOR
,
""
)
;
}
}
private
static
class
MyAsyncTask
extends
AsyncTask
<
String
,
Integer
,
String
>
{
private
String
mName
=
"AsyncTask"
;
public
MyAsyncTask
(
String
name
)
{
super
(
)
;
mName
=
name
;
}
@Override
protected
String
doInBackground
(
String
.
.
.
params
)
{
try
{
Thread
.
sleep
(
3000
)
;
}
catch
(
InterruptedException
e
)
{
e
.
printStackTrace
(
)
;
}
return
mName
;
}
@Override
protected
void
onPostExecute
(
String
result
)
{
super
.
onPostExecute
(
result
)
;
SimpleDateFormat
df
=
new
SimpleDateFormat
(
"yyyy-MM-dd HH:mm:ss"
)
;
Log
.
e
(
TAG
,
result
+
"execute finish at "
+
df
.
format
(
new
Date
(
)
)
)
;
}
}
|
下面是系统为4.1.1手机打印出的Log:很显然,我们的目的达到了,成功的让AsyncTask在4.1.1的手机上并行起来了,很高兴吧!希望这篇文章对你有用。