AsyncTask源码浅析
Posted 加冰雪碧
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AsyncTask源码浅析相关的知识,希望对你有一定的参考价值。
在开发的过程中我们如果想进行一些耗时的操作不能直接在UI线程中进行,除了使用Handler机制来进行异步消息处理,android还给我们提供了一个非常方便的类AsyncTask来进行异步操作,在这篇文章中只对AsyncTask的源码进行一下梳理,如果对AsyncTask的使用还不太熟悉的可以先看一下API的使用方法。
我们往往是定义一个类继承AsyncTask,然后创建出这个类的实例,而后调用execute方法来执行任务,我们就从这里入手来分析源码,首先是构造方法:
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask()
mWorker = new WorkerRunnable<Params, Result>()
public Result call() throws Exception
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
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);
;
首先看一下代码的注释,告诉我们这个构造器必须在UI线程中进行调用,这个在后面会给出分析。构造方法很简单,分别对创建出了WorkerRunnable和FutureTask对象并将其保存起来。先看看WorkerRunnable是什么东西:
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result>
Params[] mParams;
实现了Callable接口(可以简单的将Callable对象看做一个执行run方法时有返回值的Runnable对象,只不过在Callable中改名叫call方法),是一个抽象类,在构造函数中重写了call方法,暂时先不用考虑里面的逻辑,后面会进行分析。
再看FutureTask类,它的构造方法中接受了一个Callable参数,也就是我们刚刚创建出来的WorkerRunnable对象,看一下它的方法列表不难找到一个比较熟悉的方法,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 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对象的call方法。
构造函数已经简单的分析完了,现在来看一下我们经常调用的execute方法:
public final AsyncTask<Params, Progress, Result> execute(Params... params)
return executeOnExecutor(sDefaultExecutor, params);
可以看到,它只是简单的调用了另一个方法,但是出现了一个没有见过的参数sDefaultExecutor,来看一下这个参数是什么:
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
/**
* An @link Executor that executes tasks one at a time in serial
* order. This serialization is global to a particular process.
*/
public static final Executor SERIAL_EXECUTOR = new 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);
代码不是很多,首先在线程池中维护了一个双端队列的实例,并且在线程池的execute方法中并没有执行传入的Runnable对象,而是将它用另一个新创建的Runnable对象包装起来放到队列的尾部。显然,在第一次调用execute方法的时候mActive对象一定是null,这个时候会调用scheduleNext方法将队列中的元素拿出来,并且使用THREAD_POOL_EXECUTOR来执行它,看一下THREAD_POOL_EXECUTOR的代码:
/**
* An @link Executor that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
只是创建了一个固定规格和模式的线程池,这里不是分析的重点就不去深入它了。在执行完成后可以看到无论如何都会执行到SerialExecutor中execute方法的finally语句中,在这里又调用了scheduleNext进行重复的工作。通过上面的分析也就不难理解注释中说明的一次只能执行一个任务,虽然没有继续分析,但是可以猜想出AsyncTask的任务是由SerialExecutor进行分配,并且由于它是static的,在同一个进程内所有的AsyncTask中的任务都会放入到这个类的队列中按顺序执行。
接着回到AsyncTask的execute方法中,调用了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;
在这里可以看到熟悉的onPreExecute方法被调用了,由于前面的注释中说过,AsyncTask类对象的创建必须是在主线程中执行的,所以onPreExecute方法的执行也是在主线程中的。而后将传入的参数赋给了mWorker对象中的数组,使用传入的线程池对mFuture进行执行,因为传入的参数是sDefaultExecutor,所以执行的逻辑跳转回了SerialExecutor的execute方法,而后在线程池中执行了mFuture的run方法。根据我们前面的分析它的run方法调用了mWorker的call方法,那么call方法是在哪里实现的呢,没错,在构造函数中:
public Result call() throws Exception
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
return postResult(doInBackground(mParams));
在这里执行了doInBackground方法,这个方法应该很熟悉了,它是一个抽象的方法,也是每次都要求我们必须进行重写的。这里由于执行过程还是在线程池中进行的,所以避免了在UI线程中进行耗时操作。方法执行完成后将返回值作为参数传递给了postResult方法,进入看一下:
private Result postResult(Result result)
@SuppressWarnings("unchecked")
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
在这里面看到了很熟悉的代码,Handler机制,那么这个Handler是在哪创建的呢,
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;
很显然Handler类是静态的,在类加载的时候就会初始化这个类,现在回过头再来想一下刚才提到的AsyncTask一定要在UI线程中加载的问题,如果不在UI线程中进行加载,那么Handler自然也就不在UI线程中,那么onProgressUpdate方法和onPostExecute方法中也就不能执行更新UI的操作了。
继续看postResult方法,很简单,就是给Handler发了一个消息并且传了一个参数,而Handler调用了AsyncTask的finish方法用到了这个参数,下面是finish方法:
private void finish(Result result)
if (isCancelled())
onCancelled(result);
else
onPostExecute(result);
mStatus = Status.FINISHED;
在任务被取消时调用onCancelled方法回调,不然就调用我们熟悉的onPostExecute方法。而在Handler的handleMessage中还有一个接收项,它回调了我们常用的onProgressUpdate方法,找一下这个标记(MESSAGE_POST_PROGRESS)是怎样传入的,不难找到publishProgress方法:
protected final void publishProgress(Progress... values)
if (!isCancelled())
sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
这也正是我们在doInBackground中经常使用的。
以上是关于AsyncTask源码浅析的主要内容,如果未能解决你的问题,请参考以下文章