首页 > 代码库 > Android-AsyncTask源码分析
Android-AsyncTask源码分析
AsyncTask异步任务类,允许在UI线程中进行后台操作和发布结果到UI线程中,一般使用多操作中,这个类的基本用法可以参照博主写的另一边博文http://blog.csdn.net/nzsdyun123/article/details/22215589这里有讲述AsyncTask的基本用法,今天我也按照上篇分析Handler机制那样带领大家来分析下AsyncTask的流程。
我们一般是这样来开始启动AsyncTask的:
MyAsyncTask myAsyncTask = new MyAsyncTask();
myAsyncTask.execute(path);
这里MyAysncTask是AysncTask的子类,这里我们使用AsyncTask的时候也是一般继承AysncTask类,重写其方法,我们查看AysncTask的源码发现:
/**
* <p>AsyncTask enables proper and easy use of the UI thread. This class allows to
* perform background operations and publish results on the UI thread without
* having to manipulate threads and/or handlers.</p>
*
* <p>AsyncTask is designed to be a helper class around {@link Thread} and {@link Handler}
* and does not constitute a generic threading framework. AsyncTasks should ideally be
* used for short operations (a few seconds at the most.) If you need to keep threads
* running for long periods of time, it is highly recommended you use the various APIs
* provided by the <code>java.util.concurrent</code> pacakge such as {@link Executor},
* {@link ThreadPoolExecutor} and {@link FutureTask}.</p>
AsyncTask是后台UI线程,通过发布结果到UI线程中,同时这里也给我们介绍了AsyncTask被设计成Thread和Handler的一个助手类,适用于短时的线程操作,长时的线程操作被推荐适用线程池ThreadPoolExecutor来解决,及其他的一些基础用法等,从这里的简介中,提到AsyncTask被设计成Thread和Handler的一个助手类?我们这时就要想AsyncTask是不是对Thread+Handler的一个封装?答案是这样吗?我们带着疑问来分析:
当我们调用myAsyncTask.execute(path);这语句时,这时AsyncTask就开始正式工作了。我们来进入源码分析这句:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
这里函数被设计成接收三个泛型数据类型的类,同时参数被设计成可变参数,可以根据实际需求动态的传入参数的个数。我们接着看跟踪 return executeOnExecutor(sDefaultExecutor, params);
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {//尚未创建AsyncTask
switch (mStatus) {
case RUNNING://有AsyncTask正在后台运行,抛出异常
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED://有AsyncTask任务已完成
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;
}
从上述分析可以知道当前UI线程的AsyncTask对象不能多次调用execute方法,关键的是我们看这几句
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
追踪onPreExecute();可以发现这是一个空实现方法:
/**
* Runs on the UI thread before {@link #doInBackground}.
*
* @see #onPostExecute
* @see #doInBackground
*/
protected void onPreExecute() {
}
子类可以重写它,运行在UI线程,在doInBackground方法之前,从这里我们可以知道,既然onPreExecute函数运行在UI线程中,所以我们可以在这做些资源的初始化的工作。接着来分析 mWorker.mParams = params;这句是将参数赋值给mWorker对象的参数。所以我们追踪mWorker对象发现:
private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
它是AsyncTask的类类型对象,那WorkerRunnable到底是什么呢?追踪源码可知:
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
它是一个抽象类,实现了Callable回调接口,用于从不同的线程来获取结果Result,OK,我们接着分析:
exec.execute(mFuture);从executeOnExecutor函数声明中可以看出exec是Executor的对象,Excutor?哇,这不就是线程池的运用嘛(线程池知识这里不讲解),这里简单讲下Excutor,Excutor是一个接口,此接口提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节、调度等)分离开来的方法。简单讲就是方便线程的创建和使用。那么exec.execute(mFuture);就是执行线程,那这个mFuture肯定是一个Runnable或者实现Runnable接口的类,追踪mFuture:
private final FutureTask<Result> mFuture;
FutureTask?这又是什么呢?我们查看JDK帮助文档可知:
public class FutureTask<V>
extends Object
implements RunnableFuture<V>
它是继承了Object对象,实现RunnableFuture接口的类,当然RunnableFuture实现了Runnable接口,果不其然,由JDK可知
FutureTask是一个可取消的异步计算。利用开始和取消计算的方法、查询计算是否完成的方法和获取计算结果的方法。简单来讲就是获取提供一些方法来开始和取消线程,同时可以获取线程运行后的结果。那么FutureTask和WorkerRunnable对象又是什么时候开始创建的呢?追踪可以发现它们是在我们创建AsyncTask对象时就给我们创建好了:
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {//创建WorkerRunnable,并实现Callable接口方法call
public Result call() throws Exception {
mTaskInvoked.set(true);//设置标志值
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);//设置线程优先级
//noinspection unchecked
return postResult(doInBackground(mParams));//根据外部传入的参数调用doInBackground方法,并将结果传给postResult函数
}
};
mFuture = new FutureTask<Result>(mWorker) {
//创建FutureTask对象,重写done方法
@Override
protected void done() {
try {
postResultIfNotInvoked(get());//等到线程执行完成,通过get方法获取线程运行后的结果,传给postResultIfNotInvoked方法
} 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);
}
}
};
}
原来这两个对象在AsyncTask类创建的时候就给预先创建好了,前面说到WorkerRunnable是一个实现了Runnable接口的类,当系统执行到exec.execute(mFuture);这句时,这时就会执行线程里的WorkerRunnable的方法,这里们可以看到,AsyncTask的设计者巧妙的使用回调,将需要在线程中运行的语句又交到了我们开发应用者手上,我们查看doInBackground(mParams)就可以知道:
protected abstract Result doInBackground(Params... params);
这是一个抽象的方法,我们子类可以实现它,当然这些语句会运行在另一个线程中,Ok这时我们查看postResult和postResultIfNotInvoked方法:
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
postResultIfNotInvoked方法最后也是调用postResult方法:
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
从这里可以看出,向sHandler所在的线程发送一个消息,并将线程运行后的结果回传过去,ok,这里我们分析sHandler对象的类:
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类接收两个消息:MESSAGE_POST_RESULT线程执行完毕后消息,MESSAGE_POST_PROGRESS进度更新消息
result.mTask.finish(result.mData[0]);
我们从这句语句找到finish方法:
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
要么是调用 */
@SuppressWarnings({"UnusedParameters"})
protected void onCancelled(Result result) {
onCancelled();
}
onCancelled来取消AysncTask,不然就是等待线程运行完成后,提交给onPostExecute(result);方法处理:
@SuppressWarnings({"UnusedDeclaration"})
protected void onPostExecute(Result result) {
}
所以,我们可以在子类中重写onPostExecute这个方法时,获取其结果,而MESSAGE_POST_PROGRESS消息是将结果交于onProgressUpdate(result.mData);处理:
@SuppressWarnings({"UnusedDeclaration"})
protected void onProgressUpdate(Progress... values) {
}
这里一般是我们重写时获取进度来进行进度条更新的,那这个消息MESSAGE_POST_PROGRESS又从哪里向handler发送的呢?我们继续追查:
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
在这个方法里发送的,这就我们可以解释的同,为什么我们调用
publishProgress的时候,可以在onProgressUpdate接收结果并更新UI,publishProgress是通过handler向创建AsyncTask所在的线程中发送消息并将结果回传过去的。到目前为止,AsyncTask的源码分析就分析的差不多了,这也验证了我们刚开始的猜想,AsyncTask是对Thread+Handler的封装,当然这里不是直接使用Thread的,而已使用静态线程池来进行的,这个查看AsyncTask的各个属性声明就可以知道,当然这也带来了一些限制,那就是线程数不能创建太多。
Android-AsyncTask源码分析