1.概述
在Android中线程是一个很重要的概念,从用途来说,线程分为主线程和子线程,主线程主要去做界面的更新操作,而子线程去做耗时操作,从网络去拉取数据。在Android3.0以后开始,系统要求网络访问必须在子线程中执行,否则会报NetworkOnMainThreadException这个异常,这样做是为了避免在主线程中执行耗时操作而出现ANR异常。
对于一般线程操作,可以使用Thread+Handler,AsyncTask,HandlerThread以及IntentService,后三者的底层实现也是线程,但是他们也有特殊的表现形式,同时也有各自的优点。其中AsyncTask封装了线程池和Handler,本文主要分析下它的使用以及源码执行过程分析。
2.AsyncTask
AsyncTask是一个轻量级的异步任务类,它可以在线程池中执行后台任务,并把执行的进度和最终结果传递给主线程并在主线程中更新UI。
AsyncTask是一个抽象的泛型类,它提供了三个泛型参数Params, Progress, Result。Params是doInBackground的入口参数,Progress表示后台的任务执行进度,Result表示后台的任务返回结果。
这个类的声明如下:
public abstract class AsyncTask < Params, Progress, Result >
它主要提供了4个核心方法,含义如下:
onPreExecute()
任务开始执行之前的操作,异步任务开始之前,它会被调用,主要做任务的准备操作。
doInBackground(Params… params)
在线程池中执行,此方法主要在工作线程中,params是一个入口参数,且是一个可变参数,可以传入多个。在这个方法中,可以通过publishProgress更新任务进度,同时publishProgress会调用onProgressUpdate在主线程中更新进度。这个方法的返回值会传入onPostExecute。
onProgressUpdate(Progress… values)
任务更新操作,后台调用publishProgress,发送一个消息给handler来执行进度更新操作,在主线程中执行。
onPostExecute(Result result)
主线程中执行,异步任务之后,会返回一个Result作为onPostExecute的入口参数。
AsyncTask在具体使用过程中的条件限制:
1)AsyncTask 的类必须在主线程中创建
2)AsyncTask的对象必须在主线程中创建
3)execute方法必须在UI线程中调用
4)不要再程序中直接调用它的方法
5)一个AsyncTask对象只能执行一次,及只能调用一次execute方法,否则会报运行时异常。
6)Android 3.0以前是使用线程池中并行任务,但是在Android 3.0以后,为了出现AsyncTask的并发错误,又采用了一个线程池来串行执行任务。但是我们也可以调用AsyncTask的executeOnExecutor方法来并行执行任务。
3. 执行过程
为了查看它的执行过程,我们可以从execute方法开始分析
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
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;
}
首先我们可以看到execute,它的内部调用了executeOnExecutor,onPreExecute()被执行了,而params被封装到了mWorker中,接着exec.execute(mFuture)这个被执行,其中exec是sDefaultExecutor,看下其声明过程
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
我们可以看到SerialExecutor实现了Executor,所以exec.execute就是执行SerialExecutor的execute方法,看下其实现过程:
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
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);
}
}
}
先不分析,看下AsyncTask的构造方法
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
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);
}
}
};
}
我们可以看到实现了mWorker这个Callable接口,和实例化了mFuture这个类,并将mWorker传递给了mFuture,看下其run方法:
public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
这个callable就是mWorker,这段代码也就是说在执行run方法时,实际会调用mWorker的call方法。而刚开始的params参数被封装到了mWorker中,所以最终会在call中被执行。
再来回看SerialExecutor的execute方法,mFuture方法封装的mWorker交给它处理,首先会把FutureTask对象插入到任务队列mTask中并执行,之后如果mActive 没有正在执行的活动,就会调用SerialExecutor 的scheduleNext方法。同时当一个任务执行完毕之后,执行其他任务,直到所有任务被执行完毕,从这一点来看,AsyncTask默认是串行执行的。
刚才在构造方法中看了mWorker的匿名实现方法:
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(result);
}
首先将mTaskInvoked设为true,表示当前任务已经被执行了,然后执行doInBackground(mParams)将其返回值交给postResult执行,看下其实现过程:
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
上面代码中首先通过getHandler获取一个sHandler,如果我们看其实现过程,可以看见它是一个单例类,这里就不看了。在postResult中,发送一个MESSAGE_POST_RESULT的消息给sHandler(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;
}
}
}
可以看见MESSAGE_POST_RESULT类型消息会执行result.mTask.finish(result.mData[0])方法,而result.mTask是AsyncTask类型,也就是执行它的finish方法
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
result也就是doInBackground的执行结果返回值,如果任务被取消了执行onCancelled方法,否则执行onPostExecute方法,最后将任务状态改为FINISHED。
如果在doInBackground中调用publishProgress方法,他就会向sHandler发送一个MESSAGE_POST_PROGRESS的消息,而sHandler对于这个消息处理的方法为
result.mTask.onProgressUpdate(result.mData);
也就是执行AsyncTask的onProgressUpdate方法。
到此我们可以看见AsyncTask的几个核心方法都被执行到了,分析也就到此为止了。
4.参考
本文主要参考了《Android开发艺术探索》的线程与线程池这章。