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
24class DownloadTask extends AsyncTask<Void, Integer, Boolean>{
protected void onPreExecute(){
//可早这里进行一些初始化操作
}
protected Boolean doInBackground(Void... params){
//子线程处理后台任务,返回执行结果,这里是 Boolean
publishProgress(downloadPercent);// 从子线程切换到 UI 线程
}
protected void onProgressUpdate(Integer... values){
//方法中携带的参数就是在后台任务中传递过来的
}
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
28public 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){
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
3public 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
15public 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
3public 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
26private 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
18void 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
5private 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 | private static class InternalHandler extends Handler{ |
这里对消息的类型进行了判断,MESSAGE_POST_RESULT 就会去执行finish()
;MESSAGE_POST_PROGRESS 就会去执行onProgressUpdate()
。finish()
方法:1
2
3
4
5
6
7
8private 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
5protected 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);