1. 介绍
我们首先看下Andriod文档对AsyncTask的说明
AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
大致就是说:AsyncTask可以轻松应对有关于UI线程的任务,不需要自己去控制线程和Handler就可以实现在后台执行任务、在UI主线程通知执行结果的一个类。
An asynchronous task is defined by 3 generic types, called Params, Progress and Result, and 4 steps, called onPreExecute, doInBackground, onProgressUpdate and onPostExecute.
AsyncTask为异步任务定义了三个泛型,分别是Params, Progress and Result,然后运行流程分为四步,分别是onPreExecute, doInBackground, onProgressUpdate and onPostExecute,其中泛型声明中Param代表输入参数,Progress代表执行进度,Result代表执行结果,其流程也是围绕这三个泛型参数展开,下面我们就针对AsyncTask背后的原理进行分析。
2. 源码分析
先看一个AsyncTask的使用实例
new AsyncTask<Integer, Integer, Integer>() {
protected void onPreExecute() {
Log.i(TAG, "onPreExecute");
};
@Override
protected Integer doInBackground(Integer... arg0) {
int result = arg0[0];
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
result++;
publishProgress(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return result;
}
protected void onProgressUpdate(Integer[] values) {
Log.i(TAG, "onProgressUpdate" + values[0]);
};
protected void onPostExecute(Integer result) {
Log.i(TAG, "onPostExecute" + result);
};
}.execute(0);
实例演示了参数Param:0 从0加至10的过程,手动Sleep线程一秒并更新进度。可以看出AsyncTask流程是由execute()方法激发的,所以源码分析就从execute()方法开始。
public final AsyncTask<Params, Progress, Result> execute(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;
sExecutor.execute(mFuture);
return this;
}
1 - 14行是对AsyncTask执行状态的一个维持,也阻止了一些非法状态。
16行调用了我们熟悉的onPreExecute(),此时所在的线程就是我们new AsyncTask所在的线程,AsyncTask的构造函数的文档说明是这样的
Creates a new asynchronous task. This constructor must be invoked on the UI thread.所以AsyncTask构造函数的执行线程环境必须是UI线程,关于为什么会有如此要求我们会在后面说明,自然onPreExecute()方法也会在UI线程中调用,此方法用来说明任务开始执行,一般在界面显示一个置为0位置的进度条。
18-19行:首先把我们传入的Param赋值给WorkerRunnable的一个实例变量,然后线程执行器开始执行一个FutureTask
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
WorkerRunnable类的定义很简单,内部仅有一个mParams实例变量
下面我们看一下WorkerRunnable和FutureTask的实例对象被创建的时机,即AsyncTask的构造函数
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return doInBackground(mParams);
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
Message message;
Result result = null;
try {
result = 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) {
message = sHandler.obtainMessage(MESSAGE_POST_CANCEL,
new AsyncTaskResult<Result>(AsyncTask.this, (Result[]) null));
message.sendToTarget();
return;
} catch (Throwable t) {
throw new RuntimeException("An error occured while executing "
+ "doInBackground()", t);
}
message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(AsyncTask.this, result));
message.sendToTarget();
}
};
}
4 - 5行:更改线程优先级,并调用doInBackground(),现在所在的线程为线程执行器中开启的子线程,所以doInBackground()执行在子线程中,该方法是任务处理的主体。
11 - 34行: FutureTask的done()方法,该方法无论任务正常结束、取消、异常结束都会调用该方法,在16行调用get()方法获得任务执行结果,并把执行结果投递到InternalHandler对应的MessageQueue队列中。
下面看下InternalHandler的定义
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;
case MESSAGE_POST_CANCEL:
result.mTask.onCancelled();
break;
}
}
}
在该类中看到对各个状态的处理,这些都要在UI线程执行的方法,其中刚才说到的对执行结果的处理,是放在
private void finish(Result result) {
if (isCancelled()) result = null;
onPostExecute(result);
mStatus = Status.FINISHED;
}
中间调用了熟悉的onPostExecute(result);该方法在UI线程中执行,该方法主要用来反馈执行结果。前面说过AsyncTask的创建必须放在UI主线程,我们现在来探究一下其原因,在UI线程中执行的方法都被放置在
InternalHandler 中处理和中转,我们看下InternalHandler 实例的创建
private static final InternalHandler sHandler = new InternalHandler();
此处创建InternalHandler 使用的是InternalHandler 的空构造函数,
public Handler() {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = null;
Handler中的mLooper是通过Looper.myLooper()赋值的,该方法是获取当前所在线程的ThreadLocal中存取的Looper对象,所以当在子线程中创建AsyncTask实例的时候,在该子线程ThreadLocal并没有存入Looper,这就是为什么不能在子线程中创建AsyncTask的原因,其实并不是在子线程不能创建AsyncTask只是当前子线程不符合AsyncTask的条件。
在doInBackground()方法中有时要更新执行进度,会调用
protected final void publishProgress(Progress... values) {
sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
然后经过Handler中转到UI线程中调用onProgressUpdate方法
3. 结束语
这样关于AsyncTask的源码分析就结束了,可以看出AsyncTask也是基于Handler机制的中转,中间解释了AsyncTask不能在子线程中创建的原因,在以后的博客中会对AsyncTask进行更改使其支持在子线程创建。