背景
异步任务AsyncTask是Android里自带的异步处理任务(网络请求等)的工具类,使用起来很方便,如今记录一下我对它的源码的阅读过程。
源码取自Android8.0
使用
常见的使用方式之一如下:
AsyncTask<String, Void, String> asyncTask = new AsyncTask<String ,Void, String>() {
@Override
protected void onPreExecute() {
}
@Override
protected String doInBackground(String... strings) {
return null;
}
@Override
protected void onProgressUpdate(Void... values) {
}
@Override
protected void onPostExecute(String s) {
}
};
asyncTask.execute();
构造方法里的三个泛型参数的类型,分别是参数的类型(String),进度条的类型(Void就是没有进度条)和结果类型(String)
其他的使用方式不管是继承异步任务,还是匿名类的方式,都换汤不换药。其中那四个方法,除了doInBackground()是在子线程里执行的,也是我们必须实现的方法,其他三者都是在主线程里执行的,不必我们实现的(但用来处理结果的onPostExecute()最好还是实现)
最后的execute()不能漏掉,否则任务不会执行的。
下面我从构造方法开始,记录对其源码的阅读
源码阅读
AsyncTask构造方法
构造方法的代码如下
public AsyncTask() {
this((Looper) null);
}
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper); // 传进来的callbackLooper是null,所以mHandler一定是主线程的handler
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// 线程的优先级:后台线程
result = doInBackground(mParams);
// doInBackground()在这里执行,显然是在子线程
Binder.flushPendingCommands();
// 清空Binder命令
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result); // 给mHandler发送结果,所以结果肯定是在主线程里处理的
}
return result;
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
// 如果因为某种原因未执行任务,还是尝试把结果返回(只是这里返回的是null)
try {
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
..
} catch (ExecutionException e) {
..
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
构造方法里做了三件事:初始化handler,这个handler默认是主线程的handler、实例化mWorker,这是真正的执行任务者,实例化mFuture,用来对mWorker进行管理,来处理多个任务(默认的话,多个任务是串行处理,按照传入的顺序)
构造完了AsyncTask对象后,就调用了execute()方法执行任务
AsyncTask#execute()方法
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
.. // 异常
case FINISHED:
.. // 异常
}
}
mStatus = Status.RUNNING;
onPreExecute(); // onPreExecute()在这里被调用,所以是它在主线程里被调用的
mWorker.mParams = params; // 给worker传入参数
exec.execute(mFuture); // 执行的是mFuture对象
return this;
}
可以看到任务是在sDefaultExecutor上执行的,而sDefalutExecutor是一个串行处理器,它的定义如下
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
所以我们要看一看串行处理器是怎么执行任务的
SerialExecutor#execute()
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() {
// offer方法把对象放到队尾
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) { // poll()方法从队首取元素
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
execute()方法就是把传进来的runnable对象(这里是mFuture)放到了mTasks队列队尾,然后判断mActive,也就是当前执行的线程是否是空,是空的话,调用scheduleNext()方法从队列队首获取元素,放到THREAD_POOL_EXECUTOR中执行。
关于THREAD_POOL_EXECUTOR的定义如下
public static final Executor THREAD_POOL_EXECUTOR;
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
这就是个线程池,里面的参数都是异步任务自己设定的,代码如下
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)); // 最大并行线程数,至少是2个线程
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; // 线程池容量
private static final int KEEP_ALIVE_SECONDS = 30; // 每个线程最多执行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());
// 构造线程时,直接new
}
};
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128); // 线程队列模型是阻塞链表,容量128
关于线程池怎么工作,请参加文章安卓开发学习之线程池源码解析
执行一个线程,就是执行它的run()方法,而这里的mFuture线程是FutureTask类,所以就要看看FutureTask类的run()方法的内容
FutureTask#run()方法
public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
Callable<V> c = callable; // callable就是构造方法里传进来的worker
if (c != null && state == NEW) { // 没有执行前,state就是NEW
V result;
boolean ran;
try {
result = c.call(); // 调用worker的call()方法
ran = true; // 设置标志位
} catch (Throwable ex) {
.. // 异常
}
if (ran)
set(result); // 设置结果,不过AsyncTask处理结果是在worker的call()方法,这里没什么用处
}
} finally {
...
}
}
原来worker的call()方法是在这儿被调用的,我们回到AsyncTask的构造方法里看看worker的call()方法,会知道它执行了doInBackground()后,在finally里进行了结果的处理,也就是调用AsyncTask的postResult()方法
AsyncTask#postResult()方法
private Result postResult(Result result) {
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
// 把AsyncTask自己和任务执行结果封装成AsyncTaskResult对象
// 其中任务执行结果是作为数组保存的
message.sendToTarget();
return result;
}
private Handler getHandler() {
return mHandler;
// 在AsyncTask构造方法里,mHandler被赋值成了sHandler,因为我们传进去的callbackLooper默认是null
}
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler(Looper.getMainLooper());
}
return sHandler;
}
}
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper); // looper是主线程的looper
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// result.mTask就是AsyncTask自己,mData[0]就是要处理的结果
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS: // 刷新进度条
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result); // 执行onPostExecute()处理结果
}
mStatus = Status.FINISHED;
}
如此,从任务执行前,到任务执行时,再到结果处理,整个过程都清楚了。接下来我们看进度条的更新调用
AsyncTask#publishProgress()方法
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
这个方法需要我们在doInBackground()里调用的,不调用是不会更新进度条的。关于handler如何处理MESSAGE_POST_PROGRESS消息,请参见上文。
结语
关于异步任务的处理流程源码的阅读就是这样。