AsyncTask类是Android设计的一个执行异步方法的类,我们可以利用这个类执行一些耗时的任务,然后根据结果更新UI,在执行任务时,也可以更新UI,如设置进度条的进度等等。今天,我们从源码分析这个类,学习执行异步方法的思想,这对我写异步框架应该会起到帮助。Show me the code !!
从属性开始,我分为2部分:(1)线程池的初始化。(2)普通属性。
(1)线程池的初始化
直接看代码:
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// We want at least 2 threads and at most 4 threads in the core pool,
// preferring to have 1 less than the CPU count to avoid saturating
// the CPU with background work
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE_SECONDS = 30;
// 线程工厂,用来为线程池创建工作线程
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());
}
};
// 任务队列,当线程池的工作线程大于核心线程CORE_POOL_SIZE,新的任务便会加入到这个任务队列中,这里定义队列大小为128
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
// 真正执行任务的线程池
public static final Executor THREAD_POOL_EXECUTOR;
// 静态块
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, // 核心线程数
MAXIMUM_POOL_SIZE, // 最大线程数
KEEP_ALIVE_SECONDS, // 非核心线程闲置的时间
TimeUnit.SECONDS, // KEEP_ALIVE_SECONDS的单位
sPoolWorkQueue, // 任务队列
sThreadFactory); // 线程工厂
// 设置核心线程闲置时,超过KEEP_ALIVE_SECONDS也被销毁,这里是1秒
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
在静态块中,一开始便初始化了一个线程池。更多关于线程池,请参考我上一篇博文Android线程池浅析。
(2)普通属性
// 这个是加入任务的线程池,接下来会分析
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
// Handler处理消息的标志
private static final int MESSAGE_POST_RESULT = 0x1;
private static final int MESSAGE_POST_PROGRESS = 0x2;
// 默认执行任务的线程池,定义为SerialExecutor,待会分析
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
private static InternalHandler sHandler;
// 异步任务,待会分析
private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
// 状态
private volatile Status mStatus = Status.PENDING;
// 原子性布尔变量,用于判断是否取消和执行的标志
private final AtomicBoolean mCancelled = new AtomicBoolean();
private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
普通属性我们简单的分析了一下,上面提到SerialExecutor线程池,我们来看看代码:
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
// 将Runnable任务加入到mTasks队列中
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
// 如果没有任务在执行,就开始执行任务
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
// 从mTasks队列取出任务,并加入到THREAD_POOL_EXECUTOR线程池执行任务
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
从代码可以看出,SerialExecutor是临时保存任务的,真正执行任务的是THREAD_POOL_EXECUTOR线程池。从代码还看出,AsyncTask是串行执行的,这点很重要。还涉及到队列的小知识,如果mTasks没有元素Runnable的话,调用mTasks.poll()会返回null,不会阻塞。
属性中还定义了状态,有以下3种:
public enum Status {
/**
* Indicates that the task has not been executed yet.
*/
PENDING,
/**
* Indicates that the task is running.
*/
RUNNING,
/**
* Indicates that {@link AsyncTask#onPostExecute} has finished.
*/
FINISHED,
}
好了,属性部分到这里已经看完了,我们看看构造函数吧:
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
...
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
...
}
};
}
构造函数主要初始化mFuture,里面的实现代码再分析。为什么要使用FutureTask呢?那是因为AsyncTask任务需要可取消的功能,而FutureTask正好满足需求。关于FutureTask我也写了一篇博文,请参考FutureTask源码浅析。
我们要执行AsyncTask时,要调用它的execute,代码如下:
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
@MainThread表示要在主线程执行,至于为什么,待会我一一道来。我们继续跟踪executeOnExecutor方法:
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
// 如果当前状态不是Status.PENDING,直接报错。
// 这就表明了,一个AsyncTask只能执行一次。
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,这个方法是钩子方法,子类可以选择重写
onPreExecute();
// 把我们传入的参数交给mWorker
mWorker.mParams = params;
// 开始执行mFuture任务
exec.execute(mFuture);
return this;
}
我们先来看看mWorker。它是一个WorkerRunnable,实现Callable接口,如果你知道FutureTask,应该知道为什么要实现Callable。
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
// 定义了参数,AsyncTask就是用过这个属性,把参数传进来使用的
Params[] mParams;
}
调用exec.execute(mFuture)便开始执行任务,上面已经分析过了,其实是先加入一个队列,然后交给THREAD_POOL_EXECUTOR线程池开启线程执行。
我们看看mFuture执行任务的代码,那么得回到初始化mFuture的代码了,也就是构造函数:
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
// 设置这个任务已经在执行了
mTaskInvoked.set(true);
// 设置线程优先级,处于THREAD_PRIORITY_BACKGROUND
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// noinspection unchecked
// 这里开始执行我们子类重写的doInBackground方法
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
// 调用postResult方法,里面主要是调用
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);
}
}
};
如果你对FutureTask熟悉的话,应该知道,FutureTask执行任务会先调用Callable的call方法。上面的代码中,mWorker会先执行call方法,然后mFuture的done方法才会调用。mWorker的call方法中,先调用了我们子类重写的doInBackground方法,然后调用了postResult方法。我们看看postResult方法的代码:
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(消息机制)传到主线程。如果对消息机制不了的,可以看我写的3篇关于消息机制的博文Android消息机制(1)- 简介。getHandler得到的是主线程的Handler,代码如下:
private static Handler getHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler();
}
return sHandler;
}
}
我们再来看看自定义的InternalHandler代码:
private static class InternalHandler extends Handler {
public InternalHandler() {
// 主线程Looper
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;
}
}
}
看InternalHandler重写的handleMessage方法,主要处理2个消息事件:MESSAGE_POST_RESULT和MESSAGE_POST_PROGRESS。postResult方法传过来的是MESSAGE_POST_RESULT事件,这里涉及到一个类,AsyncTaskResult,代码:
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
其实就是一个保存数据和AsyncTask的包装类。
我们回到InternalHandler处理MESSAGE_POST_RESULT事件,调用了result.mTask.finish,从AsyncTaskResult看出,其实也就是执行AsyncTask的finish方法,代码如下:
private void finish(Result result) {
if (isCancelled()) {
// 如果任务取消了,调用onCancelled方法
onCancelled(result);
} else {
// 如果任务没有取消,调用onPostExecute方法
onPostExecute(result);
}
// 更新状态
mStatus = Status.FINISHED;
}
finish方法代码很简单,不用多说。InternalHandler还可以处理一个事件,MESSAGE_POST_PROGRESS,作用是在执行doInBackground方法时,还能通过调用publishProgress方法更新UI。
我们先看看publishProgress方法:
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
// 如果任务没有取消,分发消息给InternalHandler处理
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
主要是分发消息给InternalHandler处理,InternalHandler调用result.mTask.onProgressUpdate(result.mData)方法处理事件,也就是交给AsyncTask的onProgressUpdate方法处理。而onProgressUpdate是一个挂钩方法,交给子类去实现。
接下来给出子类可以重写和必须重写的方法,主要是看一下:
// 子类必须重写,执行异步的方法
@WorkerThread
protected abstract Result doInBackground(Params... params);
// 其他方法子类可以选择重写,挂钩方法
@MainThread
protected void onPreExecute() {
}
@SuppressWarnings({"UnusedDeclaration"})
@MainThread
protected void onPostExecute(Result result) {
}
@SuppressWarnings({"UnusedDeclaration"})
@MainThread
protected void onProgressUpdate(Progress... values) {
}
@SuppressWarnings({"UnusedParameters"})
@MainThread
protected void onCancelled(Result result) {
onCancelled();
}
@MainThread
protected void onCancelled() {
}
到这里,相信你对AsyncTask的机制已经很熟悉了。还有一个,AsyncTask是可取消的,我们看看取消的代码:
public final boolean cancel(boolean mayInterruptIfRunning) {
// 设置取消标志
mCancelled.set(true);
// 调用FutureTask的取消方法
return mFuture.cancel(mayInterruptIfRunning);
}
// 判断是否取消
public final boolean isCancelled() {
return mCancelled.get();
}
FutureTask调用cancel方法传入了一个参数,通过解读FutureTask源码可知,如果参数mayInterruptIfRunning为true的话,会立刻中断线程,并设置Interrupt标志。如果为false,则会继续等待线程执行完,设置Cancel标志。
我还在想AsyncTask的cancel方法为什么没有调用onCancelled方法呢,原来我之前对中断线程有误解,正好这里更正了我对线程中断的理解。我原以为调用Thread的interrupt()方法,run方法就不会继续往下执行,直接跳出run方法,这种想法完全是错误的。其实调用Thread的interrupt()方法,如果Thread处于阻塞状态,如处于sleep或者wait,此时,Thread就会收到中断的信号,提前终止阻塞状态,同时抛出InterruptedException异常,然后继续往下执行。如果Thread并没有阻塞,调用Thread的interrupt()方法并不会起效果,run方法还是会继续执行下去。为了证明这点,我特意写了个demo,代码:
public class MainActivity extends Activity {
// 阻塞队列
private LinkedBlockingQueue<Integer> queue;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
queue = new LinkedBlockingQueue<>();
final Thread thread = new Thread(new Runnable() {
@Override
public void run() {
int result;
try {
// 从队列取出元素
result = queue.take();
} catch (InterruptedException e) {
// 处理Interrupted异常
e.printStackTrace();
result = -1;
}
Log.e(getClass().getName(), "结果为" + result);
sayHello();
}
});
thread.start();
// 2秒后调用thread.interrupt方法
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
thread.interrupt();
}
}, 2000);
}
private void sayHello() {
Log.e(getClass().getName(), "hello, i executed ----------- ");
}
}
打印的结果如下:
从打印结果可以知道,sayHello方法还是会执行的,证明我刚才对Thread.interrupt()方法的理解是正确的。
我们再来看调用AsyncTask的cancel(true)方法(因为false不会中断任务线程),我们结合mFuture初始化代码看:
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
// 设置这个任务已经在执行了
mTaskInvoked.set(true);
// 设置线程优先级,处于THREAD_PRIORITY_BACKGROUND
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// noinspection unchecked
// 这里开始执行我们子类重写的doInBackground方法
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
// 调用postResult方法,里面主要是调用
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);
}
}
};
因为doInBackground是异步方法,一般在这里阻塞,调用FutureTask的cancel方法后,doInBackground提前结束阻塞,继续往下执行,那么postResult方法也会被执行,接着调用finish方法:
private void finish(Result result) {
if (isCancelled()) {
// 如果任务取消了,调用onCancelled方法
onCancelled(result);
} else {
// 如果任务没有取消,调用onPostExecute方法
onPostExecute(result);
}
// 更新状态
mStatus = Status.FINISHED;
}
此时isCancelled为true,所以onCancelled会被执行。这里有学到了关于线程中断的一点小知识,太激动了!!!
到此,整个AsyncTask的原理分析的差不多了,其实我们也能利用这种思想做出我们自己异步框架。我们不是重新做轮子,我们的目标是做更好的轮子。浏览了一下源码,还有个地方你应该知道:
public static void setDefaultExecutor(Executor exec) {
sDefaultExecutor = exec;
}
其实我们可以自定义AsyncTask执行任务的线程池和任务排序,默认是顺序执行,如果你想要任务按照你想要的顺序排序,可以自定义Executor,代码回忆一下:
...
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_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);
}
}
}
...
如果你并不想要重新定义顺序,只想自定义线程池,执行方法时,调用executeOnExecutor,以下是execute和executeOnExecutor的区别:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
...
}
AsyncTask源码到这里分析已经结束了,发现自己的好好补补线程和队列的知识。