五个核心方法
onPreExecute()
此方法在主线程中执行,在异步任务执行之前,此方法会被调用,一般用于一些准备工作,例如下载进度条的初始化。doInBackground(Params… params)
此方法在子线程中执行,用于执行异步任务,注意这里的params就是AsyncTask的第一个参数类型。在此方法中可以通过调用publicProgress方法来更新任务进度,publicProgress会调用 onProgressUpdate 方法。onProgressUpdate(Progress… values)
此方法在主线程中执行,values的类型就是AsyncTask传入的第二个参数类型,当后台任务的执行进度发生变化时此方法执行。onPostExecute(Result result)
此方法在主线程中执行,在 doInBackground 方法执行完成以后此方法会被调用,其中result的类型就是AsyncTask传入的第三个参数类型,它的值就是doInBackground方法的返回值。execute(Params… params)
触发异步任务的执行。publishProgress(Progress… values)
一般在doInBackground中调用,来开启进度更新
注意:
- AsyncTask的实例必须在UI线程中创建
- execute必须在UI线程中调用
- 不能在doInBackGround中更改UI组件信息
- 一个AsyncTask的实例只能执行一次任务,执行第二次会抛出异常
AsyncTask的实现基本原理
相关系统类:
LinkedBlockingQueue、ThreadPoolExecutor、Handler、Callable、FutureTask、Executors、ArrayDeque内部类:
Status:枚举类,有PENDING、RUNNING、FINISHED三种状态SerialExecutor:Executors对象,分发任务给ThreadPoolExecutor,让任务顺序执行
WorkerRunnable< Params, Result>:Callable对象,表示任务,封装执行任务的逻辑,以及返回执行结果
InternalHandler:内部的Handler,通过主线程的Looper构造。AsyncTask最后其实也是通过Handler来把结果返回给UI线程。
AsyncTaskResult:原始结果被封装入成此对象,并绑定到Message上被Handler发出去
首先我们会创建一个AsyncTask的实例:
public AsyncTask() {
//实例化一个任务实例,它实现了Callable接口,可返回结果
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
...
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(result);
}
};
//传入了Callable任务实例,封装成FutureTask,可被线程执行,任务执行完毕,调用done方法
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
...
}
};
创建好之后,已经定义好了任务体,获得结果只需要mFuture.get()即可。创建好实例,重写过相关方法后,就会调用AsyncTask实例的execute方法:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
这里有调用了executeOnExecutor,并且多了一个参数sDefaultExecutor用来分发任务,让任务顺序执行。跟踪executeOnExecutor:
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;
}
为什么AsyncTask实例只能执行一次?
从if条件判断语句看到,如果不是PENDING状态就会抛出异常。而在AsyncTask实例初始化时,mStatus会被置为PENDDING。继续往下看,只要调用execute,状态就会变为RUNNING。
代码逻辑跳入exec.execute(mFuture),exec为SerialExecutor实例,参数为FutureTask实例。因此,接下来查看SerialExecutor类:
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
//核心方法,参数为Runnable。FutureTask实现了Runnable接口(实际上是RunnableFuture接口)
public synchronized void execute(final Runnable r) {
//加入任务到队尾。并且,重新封装任务,加入scheduNext方法,使每个任务执行完后,自动执行取队首任务执行。
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) {
//真正线程执行任务的地方
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
到这里似乎断了,因为发现调用没有返回结果的方法。这里要提到FutureTask,在调用exec.execute(mFuture)后,在构造方法中创建的mFuture被传入exec对象,上面被最终执行的mActive其实引用的是FutureTask对象,FutureTask是个可管理的异步任务,任务执行完之后,会调用done方法,之后获取结果,又最终调用到postResult传递结果到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传递消息,最后查看InternalHandler类:
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;
}
}
}
如果任务正在执行,则最终调用onProgressUpdate,若任务执行完毕则最终调用到onPostExecute
既然Asynctask的实例一次只能执行一次,那么要执行多次任务怎么办?
那就创建多个Asynctask实例来执行任务啊,另外,任务分发器sDefaultExecutor、线程池THREAD_POOL_EXECUTOR、内部Handler:InternalHandler都是静态的,虽然创建了多个实例,但是这些都是共享的。
在Android1.6之前,AsyncTask是串行执行任务,在1.6以后,改为在线程池里并行处理任务,在3.0以后,又改为在线程池里串行执行任务。
推荐阅读:
Android AsyncTask 源码解析
都是鸿洋大神写的,很赞~