AsyncTask源码解析
Posted 孙晓凯
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AsyncTask源码解析相关的知识,希望对你有一定的参考价值。
虽然关于AsyncTask的文章有很多,并且文章对AsyncTask褒贬不一,本文关注的是AsyncTask的实现原理,以及它的优缺点,至于它的好坏,请读者自行辨别。
什么是AsyncTask
AsyncTask是android框架为开发者提供的一个辅助类(只是一个类,不是库)。
AsyncTask有什么用
AsynTask的出现主要是为了解决主线程和异步线程之间的交互问题的,说到这大家是不是想到了Handler,子线程,线程池等一些列的东西?如果没有,那说明你还是太嫩啊!
其实AsyncTask就是Handler,子线程,线程池等技术的封装,为的是让android开发者处理异步更方便,现在的开源库也是这个道理。
AsyncTask怎么使用
AsyncTask的使用非常简单,读者可以自行查找相关资料,如:官方文档。
AsyncTask源码分析
在执行异步任务的时候,我们首先会调用:
new mAsyncTask().execute();
因此,我们就从这里下手!
首先让我们来看看execute()
方法中的逻辑:
public final AsyncTask<Params, Progress, Result> execute(Params... params)
return executeOnExecutor(sDefaultExecutor, params);
是不是一看就惊了个呆,竟然只有一行代码,有一行代码不代表它简单,接下来我们看看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;
我们看到代码中有一个if语句:
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代表当前的运行状态,如果一个我们的asynctask正在运行,这时我们再一次执行了excute方法,就会引发throw new IllegalStateException("Cannot execute task:"
,而如果我们的asynctask已经运行结束了,这是我们再一次运行了excute方法,就会触发
+ " the task is already running.");throw new IllegalStateException("Cannot execute task:"
异常,通过这段代码,我们应该可以明白,为什么excute方法只能被执行一次。
+ " the task has already been executed "
+ "(a task can be executed only once)");
接下来代码把状态设置为 mStatus = Status.RUNNING;
:这是因为如果没有异常,当然是正在执行啦。
接着我们就看到了我们非常熟悉的方法:onPreExecute();
(如果不熟悉,说明你还没有掌握AsyncTask的应用,就先不要看源码了,先学应用,一步一步来),这也说明了这个方法是首先被调用的,并且是在主线程中执行的。
接着往下看,出现了一行mWorker.mParams = params;
这样的代码,params我们可以知道,就是我们excute(Params…param)方法中传过来的参数,可是mWorker
又是什么呢?我们点进去看看:
private final WorkerRunnable<Params, Result> mWorker;
发现这是一个WorkerRunnable对象,那WorkerRunnable对象又是啥玩意,我们再点进去:
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result>
Params[] mParams;
额,原来实现了Callable接口,其中Callable接口中有一个call()方法。
我们再来看看mWorker是怎么进行实例化的:
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);
;
可以发现call()方法返回了Result,那Result从哪里来呢,唉 唉 唉 !!!,好像又发现了一个熟悉的方法:Result result = doInBackground(mParams);
,不过据说这个方法是在子线程中执行的,在这也没见开子线程啊,这是怎么回事?这个等会再说。
我们接着向下分析,执行到了exec.execute(mFuture);
这行代码,此时出现了个mFuture,这是什么东西呢?
private final FutureTask<Result> mFuture;
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);
;
它就相当于一个线程任务(Runnable);
exec是什么东西呢?
是executeOnExecutor(sDefaultExecutor, params);
中传过来的参数,sDefaultExecutor是啥呢?对,点进去看看:
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
额,原来是一个Executor
对象,去看看这是个什么对象:
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);
其实这就是一个线程池,线程池中的任务就是mFuture:当传入一个任务后,execute方法会首先把该任务添加到mTasks
中,
if (mActive == null)
scheduleNext();
这段代码表示,如果当前没有正在活动的任务,就调用scheduleNext()执行下一个AsyncTask任务,并且当一个任务执行完后,会继续调用下一个任务进行执行,直到执行完所有的任务为止,从这一点也可以看出AsyncTask是串行的。
其实在AsyncTask中有两个线程池,一个是SerialExecutor
,另一个是THREAD_POOL_EXECUTOR
,前者用于任务的排队,后者用于任务的执行。
还记得在上面我们遗留了一个问题,就是从哪里可以看出来doInBackground(mParams)是在子线程中执行?我们再来分析一下这段代码:
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);
;
在此看到这些代码,是不是悟到了什么?doInBackground(mParams)
在mWorker中,mWorker传给了mFuture,mFuture又加入到了线程池中,接着返回了postResult(result)
方法,此方法我们也非常熟悉,就是把结果又返回到了主线程,我们看看这个方法具体是如何做的:
private Result postResult(Result result)
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
这段代码是不是面熟,对,就是Handler发送消息,它发送了一个MESSAGE_POST_RESULT
消息,接下来我们再看看它发送到的Handler是怎么对消息进行处理的:
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;
我们可以发现,Handler是静态的,并且Handler必须在主线程中进行创建,静态成员是在类进行加载的时候进行初始化的,这也间接说明了AsyncTask必须在主线程中进行加载,handler收到MESSAGE_POST_RESULT
消息后,会执行result.mTask.finish(result.mData[0])
方法:
private void finish(Result result)
if (isCancelled())
onCancelled(result);
else
onPostExecute(result);
mStatus = Status.FINISHED;
此逻辑表示,如果我们取消了任务,就不再执行onPostExecute(result)
方法,否则,就把结果传给onPostExecute(result)
.
OK,到此为止,我们平时用的三个方法在源码中都见到了,但是需要注意的是对于AsyncTask来说,google在不同的版本中改动是比较频繁的,本文用的是API23,对于其他的版本请读者按照同样的分析方式自行分析即可。
当然,AsyncTask有很多的缺点,但是根据使用场景的不同,我们可以想办法避免这些缺点,对于AsyncTask的一些缺点,请参考Android中糟糕的AsyncTask
如文章有错误,请留言告知
以上是关于AsyncTask源码解析的主要内容,如果未能解决你的问题,请参考以下文章