在上一篇AsyncTask源码分析中为大家做了一些基础知识的铺垫,这篇就为大家真正解析一下AsyncTask源码:
首先为大家介绍一些AsyncTask的一些特性:
1、AsyncTask在3.0版本以后默认是串行的
2、AsyncTask不能在非UI线程中创建
3、AsyncTask任务数量上限是128个
4、AsyncTask只适合短时间几秒的耗时操作,不适合长时间的
耗时操作,原因是AsyncTask默认是串行的,如果你一个操作执行几分钟,那么其他的任务就根本没有办法执行
5、每个AsyncTask创建一次只能使用一次
首先大家看一下:
/**
* 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
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(result);
}
};
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);
}
}
};
}
这是AsyncTask的构造方法,在上面的注释中我们看到AsyncTask必须在UI线程中创建,却没有说为什么。只是初始化了两个对象mWorker,mFuture.
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
mWorker实际上是一个实现了Callable接口的类罢了,mFuture也不过是一个FutureTask类。暂时没有发现什么用那我们接着往下看:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
当你执行一个任务必然会调用execute方法,那这个方法最终调用的是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;
}
看到这里大家一定会看到一个熟悉的方法,onPreExecute(),这个方法经常用来做一些提前的操作,这里大家明白为什么可以提前操作了,因为它允许在主线程里。这里也解释了为什么AsyncTask创建一次只能用一次,因为AsyncTask是有状态的,运行之后的状态为Running就会报错,只有状态为Pending的时候才能继续运行下去。params是传进来的参数,sDefultExecutor是什么呢?
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
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);
}
}
}
这个sDefaultExector这个方法里面所有的逻辑操作都是在子线程中执行的,并且是串行的,这也是为什么AsyncTask默认是串行执行的原因所在。我来分析一下这个串行执行的奥秘。
1、FutueTask对象通过offer()方法添加进ArrayQueue数组队列中
2、mActivie == null
3、scheduleNext方法中
4、通过poll()方法取出,赋给mActivie,通过线程池ThreadPoolExecutor去执行
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
5、执行FutureTask里面的run()方法里面的内容,其实最终执行的是Callable()接口里面call()方法里面的内容,就是这里传入的mWorker对象里面call()方法里面的内容
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);
}
};
大家惊讶的在这里发现了我们熟悉的doInBackgroud(mParams)方法,所以doInBackgroud()内容才能在后台操作,因为这个方法是在子线程中执行的,接着讲执行的结果返回了出去,调用了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;
}
看到postResult方法里面的内容,大家惊讶的发现了Handler的身影,我们仔细看一下getHandler()方法的源代码:
private static Handler getHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler();
}
return sHandler;
}
}
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用的是主线程的Looper,这下大家明白为什么AsyncTask方法必须在主线程中创建了吧。在handleMessage方法里面我们看到有两种状态一种是MESSAGE_POST_PROGRESS,调用的是更新进度的方法,为什么能够直接更新UI,其实就是利用了Handler进行了线程的切换。还有另外一种状态是MESSAGE_POST_RESULT,大家看看这个状态最终调用了finish()
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
大家又看到了onPostExecte这个方法,现在大家对AsyncTask的执行过程有了基本的了解,我们回头来解析完AsyncTask串行的秘密。
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);
}
}
}
调用完FutureTask对象的run()方法之后,谷歌的工程师在这里做了一个绝妙的处理,利用了Java当中捕获异常当中的finally绝对会执行的特性,在finally中又再次调用了sheduNext方法,形成了一个如果ArrayQueue这个方法中如果有消息就绝对会执行完成的变异递归,如果没有了,那么mActive又会立刻为null,一旦mActive为null,又会再次走刚刚那套流程。但无论如果,每次都只有一个对象被执行。这就是AsyncTask串行的秘密。
另外为大家讲述一些AsyncTask常用的API:
public final boolean cancel(boolean mayInterruptIfRunning) {
mCancelled.set(true);
return mFuture.cancel(mayInterruptIfRunning);
}
其实这个就是调用了mFuture的cancle()方法,我们经常在一个Activity销毁的时候调用这个方法,免得消息没有处理完,AsyncTask因为无法得到回收。造成内存泄漏
public static void setDefaultExecutor(Executor exec) {
sDefaultExecutor = exec;
}
其实这边就是刚才讲的设置默认的Executor,通过设置这个可以将AsyncTask变成并发的。