AsyncTask机制详解
AsyncTask用法回顾
AsyncTask类主要用到的几个内部回调函数有:doInBackground()、onPreExecute()、onPostExecute()、onProgressUpdate()。正是这几个回调函数构成了AsynTask类的使用逻辑结构。
注意:每个AsyncTask子类必须至少复写doInBackGround()方法。
函数名
解释
onPreExecute()
准备运行(该回调函数在任务被执行之后立即由UI线程调用。这个步骤通常用来完成在用户UI上显示进度条等相关操作)。
doInBackground(Params...)
正在后台运行(该回调函数由后台线程在onPreExecute()方法执行结束后立即被调用。通常在这里执行耗时的后台计算。计算的结果必须由该函数返回,并被传递到onPostExecute()中处理。在该函数内也可以使用
publishProgress()来发布进度值,这些进度值将会在onProgressUpdate()中被接收并发布到UI线程)。
onProgressUpdate(Progress...)
进度更新(该函数由UI线程在publishProgress()方法调用完后被调用,一般用于动态地更新一个进度条)。
onPostExecute(Result )
完成后台任务(当后台计算结束后被调用,后台计算的结果会被作为参数传递给这一函数)。
函数回调关系:
image.png
通过上方函数调用关系,我们可以总结出一些数据传递关系。如下:
- execute( )向doInBackground( )传递数据。
- doInBackground( )的返回值会传递给onPostExecute( )。
- publishProgress( )向progressUpdate( )传递。
为了调用关系明确及安全,AsyncTask类在继承时要传入3个泛型:
public class MyAsyncTask extends AsyncTask<Params, Progress, Result>
• 第一个泛型对应execute( )向doInBackground( )传递的数据类型。
• 第二个泛型对应publishProgress( )向progressUpdate( )传递的数据类型。
• 第三个泛型对应doInBackground( )的返回值类型,此返回值将传递给onPostExecute( )方法。
AsyncTask运行机制梳理
AsyncTask在调用execute方法后,任务开始执行:
frameworks\base\core\java\android\os\AsyncTask.java
……
private static final ThreadPoolExecutor sExecutor =
new ThreadPoolExecutor(CORE_POOL_SIZE,MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
……
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
// 一个AsyncTask任务仅能被执行一次,不能重复执行的限制
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;
sExecutor.execute(mFuture);
return this;
}
从这段代码我们可以得出以下结论:
- 一个AsyncTask任务只能被执行一次,不能重复execute
- 调用AsyncTask的execute方法时,实际上是调用了线程池Executor的execute方法
Executor的execute方法应该接收的是一个Runnable对象,AsyncTask代码中,我们传递的是一个mFuture,那么这个mFuture是什么呢?
frameworks\base\core\java\android\os\AsyncTask.java
……
private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
……
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;
……
result = get();
……
message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(AsyncTask.this, result));
message.sendToTarget();
}
};
}
在AsyncTask的构造方法中,分别初始化了一个WorkerRunnable的对象mWorker,以及一个FutureTask的对象mFuture。我们先从mFuture开始,看看这两个做了些什么。
libcore\luni\src\main\java\java\util\concurrent\FutureTask.java
public class FutureTask<V> implements RunnableFuture<V>
libcore\luni\src\main\java\java\util\concurrent\RunnableFuture.java
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
从上面2个类,我们可以得知,FutureTask实际上是实现了Runnable接口和Future接口的一个类,因此当执行”sExecutor.execute(mFuture);
”时,也一定是执行的mFuture中的run方法。FutureTask是一个增强版的Runnable,他除了Runnable还实现了Future接口,Future接口又是做什么的?
libcore\luni\src\main\java\java\util\concurrent\Future.java
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
简单来说,Future接口就是定义任务取消、是否取消,是否完成、获取结果的一个接口。
既然知道了mFuture是一个FutureTask,即是一个增强版的Runnable,那么线程池Executor必然也是通过执行其run方法来实现相应的逻辑的,我们来看一下FutureTask的run方法做了什么:
libcore\luni\src\main\java\java\util\concurrent\FutureTask.java
private final Sync sync;
……
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
sync = new Sync(callable);
}
……
public void run() {
sync.innerRun();
}
……
由代码可知,FutureTask的run方法实际上是调用了Sync类的innerRun方法,而Sync是在FutureTask构造方法中进行的初始化,那么回忆一下AsyncTask构造方法初始化的过程,我们在构建mFuture对象的时候传递了一个WorkerRunnable的对象mWorker:
frameworks\base\core\java\android\os\AsyncTask.java
……
private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
……
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) {
……
};
}
mWorker是WorkerRunnable的一个子类,并实现了其call()方法,在这个call()方法中,我们看到了一个很关键的代码“return doInBackground(mParams);”,因此可以猜想,最终实际运行在线程池中的逻辑,实际上是这个mWorker的call()方法。
那么WorkerRunnable又是什么呢?
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
libcore\luni\src\main\java\java\util\concurrent\Callable.java
public interface Callable<V> {
V call() throws Exception;
}
由代码可知,WorkerRunnable是Callable<V>接口的一个子类,他只有一个抽象方法:call方法,这个方法是有返回值的,他返回一个泛型V。
带入到我们的实际代码逻辑中,在我们的mWorker中,这个call方法返回了我们doInBackground方法执行的结果。
知道了mWorker是什么,我们返回来看FutureTask的对象mFuture中的逻辑:
libcore\luni\src\main\java\java\util\concurrent\FutureTask.java
private final Sync sync;
……
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
sync = new Sync(callable);
}
……
public void run() {
sync.innerRun();
}
……
它将mWorker这个Callable<V>的子类作为参数,初始化了一个内部类Sync对象,并在run方法中调用了这个Sync对象的innerRun方法。
我们来看看Sync是什么:
private final class Sync extends AbstractQueuedSynchronizer {
……
private final Callable<V> callable;
private V result;
……
Sync(Callable<V> callable) {
this.callable = callable;
}
……
void innerRun() {
……
if (getState() == RUNNING) { // recheck after setting thread
V result;
try {
result = callable.call();
} catch (Throwable ex) {
setException(ex);
return;
}
set(result);
}
……
}
……
protected void set(V v) {
sync.innerSet(v);
}
void innerSet(V v) {
……
result = v;
releaseShared(0);
done();
return;
}
}
Sync对象的innerRun方法调用了“result = callable.call();”,并将得到的result最终通过innerSet方法进行了赋值,最终走到了“done()”方法。
Callable实际上就是我们的WorkerRunnable对象mWorker,这个call方法,实际上就是我们的mWorker的call方法:
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return doInBackground(mParams);
}
};
这个call方法中,我们实际上调用了doInBackground方法,并得到了这个方法运行的结果:result。
doInBackground方法运行结束后,我们通过set方法,最终调用到了innerSet方法,在这innerSet方法中,我们最终调用了FutureTask 的对象mFuture 的done方法:
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
Message message;
Result result = null;
……
result = get();
……
message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(AsyncTask.this, result));
message.sendToTarget();
}
};
我们看到done方法通过一个sHandler对象发送了一个Message,看下这个sHandler对象的handleMessage方法做了什么:
private static final InternalHandler sHandler = new 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;
}
}
}
可以看到,在what = MESSAGE_POST_RESULT的时候,他执行了:
result.mTask.finish(result.mData[0]);
这个finish方法其实调用的是当前这个AsyncTask的finish方法,这个finish方法中,调用了我们的onPostExecute方法,且因为是通过Handler发消息来调用的,因此这个onPostExecute方法当前运行到了主线程。代码如下:
private void finish(Result result) {
if (isCancelled()) result = null;
onPostExecute(result);
mStatus = Status.FINISHED;
}
因此,由上方代码得到结论:
-
onPreExecute():UI线程执行。在execute(Params... params)被调用后立即执行,一般用来在执行后台任务前的一些初始化操作
-
doInBackground(Params... params):子线程执行。在onPreExecute()完成后加入到线程池等待执行,用于执行耗时操作,此方法将接收到execute传递的参数。任务执行完毕,返回结果。
-
onPostExecute(Result result):UI线程执行。当后台操作结束时,此方法将会被调用,doInBackground返回的Result将做为参数传递到此方法中,可以执行收尾操作。
AsyncTask跟Handler谁更轻量
AsyncTask实际上是线程池 + Handler的结合,使用起来是AsyncTask更方便一些,但是使用时还是Handler更轻量一些。
细节
AsyncTask在3.0以后改为默认串行执行了,3.0以前是默认并行执行。
网友评论