在Android - Handler 、AsyncTask(一)一文中,我们提到,为了解决不能阻塞主线程和不能在子线程中更新UI的问题,Android提供了handler消息机制。
那么,如果有很多耗时的操作需要进行,并且需要在操作执行完之后或者是在操作过程中更新UI呢?创建很多线程吗?根据我们学过的知识,这个时候可以考虑使用 线程池+handler 组合的方式了(线程池在本篇博文中暂不总结),而Android已经为我们提供了相应的类来实现我们的需求,这个类就是 AsyncTask
二、AsyncTask的实现原理
通常,我们使用AsyncTask的步骤如下:
1、创建一个类myAsyncTask继承AsyncTask
A、选择性地复写onPreExecute()方法,该方法在UI线程中被执行,可以做一些初始化的工作,比如在界面上创建一个进度条。
B、(必须)复写doInBackground()方法,将耗时的操作定义在这个方法中,该方法会在onPreExecute()方法执行之后立即执行。
C、选择性地复写onProgressUpdate()方法,(任何时候都可以)在doInBackground()方法中执行publishProgress()方法来调用onProgressUpdate()方法以实现在耗时的操作过程中更新UI
D、(必须)复写onPostExecute(Result)方法,利用doInBackground()方法执行完之后返回的结果更新UI。
2、创建myAsyncTask类的实例myAsyncTaskInstance
3、执行myAsyncTaskInstance.execute(Params...)
需要注意的是:
a、AsyncTask类的实例只能在UI线程中创建
b、execute方法只能在UI线程中调用
c、不能手动调用onPreExecute()、onPostExecute(Result)、onProgressUpdate()和doInBackground()这几个方法
d、一个AsyncTask的实例只能执行一次execute方法
那么,AsyncTask的具体实现到底是什么样的呢?我们就从execute()方法的调用开始疏理
- public final AsyncTask<Params, Progress, Result> execute(Params... params) {
- return executeOnExecutor(sDefaultExecutor, params);
-
-
-
- }
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;
- }
关于上边第19行的onPreExecute()方法,在AsyncTask类中的定义及注释如下:
-
-
-
- protected void onPreExecute() {
-
- }
那上边的代码中mWorker和mFuture分别代表什么呢?
我们创建myAsyncTask类的实例时,在AsyncTask的构造函数中就已经完成了对mWorker和mFuture两个对象的初始化,mWorker是AsyncTask内部实现了Callable接口的一个类WorkerRunnable的实例:
- private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
- Params[] mParams;
- }
mWorker.mParams = params;这条语句将我们调用execute(Params...)方法时传入的参数赋值给了mWorker的成员变量mParams ,
mFuture则是FutureTask的一个实例,FutureTask的继承关系如下:
public class FutureTask<V> implements RunnableFuture<V>
public interface RunnableFuture<V> extends Runnable, Future<V>
即mFuture是Runnable的一个间接子类对象。
关于mWorker和mFuture,暂时讲到此,等后边涉及到时再来详解。
接下来,看exec.execute(mFuture)这条语句
从上文的分析中得知,执行exec.execute(mFuture)会调用SerialExecutor的execute方法,
来看SerialExecutor的完整类定义:
- 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);
- }
- }
- }
关于THREAD_POOL_EXECUTOR:
- public static final Executor THREAD_POOL_EXECUTOR =
- new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
- TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
-
-
- private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
- private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
- private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
- private static final int KEEP_ALIVE = 1;
-
- private static final ThreadFactory sThreadFactory = new ThreadFactory() {
- private final AtomicInteger mCount = new AtomicInteger(1);
-
- public Thread newThread(Runnable r) {
- return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
- }
- };
-
- private static final BlockingQueue<Runnable> sPoolWorkQueue =
- new LinkedBlockingQueue<Runnable>(128);
THREAD_POOL_EXECUTOR.execute(mActive):
将Runnable的间接子类对象mFuture交由线程池THREAD_POOL_EXECUTOR处理
那么,我们为什么不直接用THREAD_POOL_EXECUTOR来处理一个任务呢?
事实上,我们在使用AsyncTask时,有两种执行任务的方式可以选择:
1、调用public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,Params... params)方法,指定参数exec为THREAD_POOL_EXECUTOR来执行mFuture任务。
2、直接调用execute(Params... params)方法,这种方式较常用。
在采用第二种方式的情况下,任务会被SerialExecutor的execute方法重新调度之后再由THREAD_POOL_EXECUTOR来进行有序的执行,上文中我们也提到过SerialExecutor的execute方法被synchronized关键字所修饰。这种设计为我们的任务执行提供了更多的选择。
(关于这两种执行方法的区别以及和线程池相关的其他知识,将在其他博文中总结)
根据线程池的相关知识可知,接下来,要执行的就是Runnable的间接子类对象mFuture的run方法了。
同时,上文提到的,AsyncTask的构造函数中mWorker和mFuture这两个对象的初始化的代码也需要贴出来了:
- public 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) {
- @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 occured while executing doInBackground()",
- e.getCause());
- } catch (CancellationException e) {
- postResultIfNotInvoked(null);
- }
- }
- };
- }
这里还有一个问题,为什么不把要在后台执行的任务定义在一个runnable对象的run方法中然后再执行THREAD_POOL_EXECUTOR.execute(runnable),而要把任务(doInBackground()方法)定义在mWorker的call方法中,将mWorker作为参数构造出一个mFuture,然后执行execute(mFuture)呢?
我们来看一下FutureTask类的定义:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public class FutureTask<V> implements RunnableFuture<V> {
-
- }
可以看出,FutureTask类的存在是为了对一个任务进行包装,为的是能够更好地控制这个任务。
FutureTask类有两个构造函数:
第一个:
- public FutureTask(Runnable runnable, V result) {
- this.callable = Executors.callable(runnable, result);
- this.state = NEW;
- }
Executors类中的callable(runnable, result)方法:
- public static <T> Callable<T> callable(Runnable task, T result) {
- if (task == null)
- throw new NullPointerException();
- return new RunnableAdapter<T>(task, result);
- }
Executors类中的内部类RunnableAdapter:
-
-
-
- static final class RunnableAdapter<T> implements Callable<T> {
- final Runnable task;
- final T result;
- RunnableAdapter(Runnable task, T result) {
- this.task = task;
- this.result = result;
- }
- public T call() {
- task.run();
- return result;
- }
- }
可以看到,这个构造函数将接收的Runnable task和T result作为参数构造出一个Callable的间接子类对象,并且该对象的call方法中执行的就是task的run方法。然后将这个对象赋给了FutureTask的成员变量callable。
第二个
(也就是我们AsyncTask中的FutureTask走的构造函数):
- public FutureTask(Callable<V> callable) {
- if (callable == null)
- throw new NullPointerException();
-
- this.callable = callable;
- this.state = NEW;
- }
和第一个构造函数一样,重点也是在 为FutureTask的成员变量callable赋值
接下来,
mFuture 的run方法:
- public void run() {
- if (state != NEW ||!UNSAFE.compareAndSwapObject(this, runnerOffset,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 = null;
-
-
- int s = state;
- if (s >= INTERRUPTING)
- handlePossibleCancellationInterrupt(s);
- }
- }
根据上边的分析可知,FutureTask类是Runnable的间接子类对象,它复写了run方法,不过,在它的run方法中,真正的任务是在FutureTask的成员变量callable的call方法中执行的,其余代码的作用是为了更好地控制任务的执行,即FutureTask类的注释中提到的。
而AsyncTask中mFuture的创建——mFuture = new FutureTask<Result>(mWorker)——走的是上文提到的FutureTask的第二个构造函数,mWorker是WorkerRunnable类型的实例,关于WorkerRunnable的定义,上文已经列出,WorkerRunnable实现了Callable接口,并复写了call方法。
所以,THREAD_POOL_EXECUTOR.execute(mActive)的执行最终导致mWorker的call方法的执行,具体逻辑为:
- mWorker = new WorkerRunnable<Params, Result>() {
- public Result call() throws Exception {
- mTaskInvoked.set(true);
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-
-
- return postResult(doInBackground(mParams));
- }
- };
终于看到了我们的doInBackground()方法了,顺便看一下这个方法
在AsyncTask.java中的定义吧:
-
-
-
-
-
-
-
-
-
-
- protected abstract Result doInBackground(Params... params);
看到这里,也就明白了AsyncTask是怎样把我们定义到doInBackground()方法中的任务放到后台去执行的了。doInBackground()方法执行完之后,其返回值将作为postResult()方法的参数,来看postResult()方法:
- private Result postResult(Result result) {
- @SuppressWarnings("unchecked")
- Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
- new AsyncTaskResult<Result>(this, result));
- message.sendToTarget();
- return result;
- }
该方法的主要逻辑就是:
创建一条消息
(
其
what值为MESSAGE_POST_RESULT,obj值为new AsyncTaskResult<Result>(this, result))
),并且发送出去。
sHandler是AsyncTask的成员变量private static final InternalHandler sHandler = new InternalHandler();
InternalHandler是AsyncTask的内部类,
AsyncTaskResult也是AsyncTask的内部类 :
- private static class AsyncTaskResult<Data> {
- final AsyncTask mTask;
- final Data[] mData;
- AsyncTaskResult(AsyncTask task, Data... data) {
- mTask = task;
- mData = data;
- }
- }
代码比较简单,需要发送的消息的obj值就是一个AsyncTaskResult对象,其成员变量final AsyncTask mTask的值为this,成员变量final Data[] mData的值则是doInBackground()方法的返回值。消息创建好,并且发送出去了,我们来看一下消息的处理:
- 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:
-
-
- result.mTask.finish(result.mData[0]);
- break;
- case MESSAGE_POST_PROGRESS:
- result.mTask.onProgressUpdate(result.mData);
- break;
- }
- }
- }
消息处理方式为
result.mTask(即该AsyncTask对象)的finish方法(),参数为result.mData[0](即doInBackground()方法的返回值),来看finish方法()的具体逻辑:
- private void finish(Result result) {
- if (isCancelled()) {
- onCancelled(result);
- } else {
-
- onPostExecute(result);
- }
- mStatus = Status.FINISHED;
- }
再来看onPostExecute(result)方法的定义:
-
-
-
-
-
-
-
- @SuppressWarnings({"UnusedDeclaration"})
- protected void onPostExecute(Result result) { }
复写onPostExecute()方法利用doInBackground(Params...)方法的返回值更新UI的流程也梳理清楚了
现在来分析一下,如果我们 在doInBackground()方法中执行publishProgress()方法来更新UI 的话,代码的执行逻辑又是什么样的?
publishProgress()方法的定义如下:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- protected final void publishProgress(Progress... values) {
- if (!isCancelled()) {
- sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
- new AsyncTaskResult<Progress>(this, values)).sendToTarget();
- }
- }
publishProgress()方法和我们上边讲到过的postResult()方法一样,主要逻辑都是创建一条消息并且发送出去。只是在这里,消息的what值是MESSAGE_POST_PROGRESS,消息的obj值为new AsyncTaskResult<Progress>(this, values),消息的处理:
- public void handleMessage(Message msg) {
-
- AsyncTaskResult result = (AsyncTaskResult) msg.obj;
- switch (msg.what) {
- ... ...
-
- case MESSAGE_POST_PROGRESS:
- result.mTask.onProgressUpdate(result.mData);
- break;
- }
- }
和wha
t值为MESSAGE_POST_RESULT的消息的处理类似,直接看 onProgressUpdate() 方法的定义:
-
-
-
-
-
-
- @SuppressWarnings({"UnusedDeclaration"})
- protected void onProgressUpdate(Progress... values) {
至此,AsyncTask的实现原理基本清楚了,
onPreExecute()、doInBackground()、publishProgress()、onProgressUpdate()和onPostExecute(Result)这几个方法在一次AsyncTask任务执行过程中所扮演的角色也明了了
还有两个主要问题:
1、AsyncTask使用线程池+handler组合的方式,AsyncTask的缺陷或者说它的灵活使用主要也是在线程池上。关于这方面,需要另写博文作总结。
2、关于FutureTask类是怎样对callable的call方法(任务)进行控制的,还有很多细节没有搞清楚。