(注意:本文基于API 28的源码分析,API 29上或其他平台的源码略有不同)
疑问1、调用AsyncTask的execute()方法后,onPreExecute()方法、doInBackground()方法、onPostExecute()方法,这些方法按照先后顺序会被回调,这些方法是如何被回调的?整个流程是怎么样的呢??
疑问2、为什么onPreExecute()、onPostExecute()方法是在UI线程调用的?而doInBackground()方法是在工作线程调用的?
疑问3、为什么调用了publishProgress()方法,onProgressUpdate()方法会在UI线程中被回调?
本篇文章将会从源码分析,解决这三个疑问……
AsyncTask中可以重写的部分方法
上方截图是继承AsyncTask后子类可以重写的部分方法,onPreExecute、onPostExecute、onProgressUpdate、doInBackground是我们经常重写的方法!每次继承AsyncTask后,唯一要求必须重写的是doInBackground方法
继承AsyncTask,重写必须重写的doInBackground()方法
public class TempTask extends AsyncTask<Void, Void, Boolean> {
@Override
protected Boolean doInBackground(Void... params) {
…………省略好多代码…………
}
}
AsyncTask的三个参数类型的官方解读
Params:在执行时发送给任务的参数的类型
Progress:在工作线程计算期间的进度单元的类型
Result:在工作线程计算结束后结果的类型
主线程执行的execute()方法分析
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
开发者用于执行任务的方法,该方法必须在主线程中调用
1、内部先调用了一个executeOnExecutor()方法,并传入AsyncTask对象持有的sDefaultExecutor、以及传入的可变参数params
2、向调用者返回executeOnExecutor()方法的结果
主线程中执行的executeOnExecutor()过程分析
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
………………省略很多源码………………
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
1、onPreExecute()方法在该方法内部得到调用,说明onPreExecute()最先被调用,同样在主线程中被调用,开发者可以重写onPreExecute()方法,作为任务执行前的准备工作(这是疑问1、疑问2的部分答案)
2、在onPreExecute()方法执行结束后,还没有看到doInBackground()方法的执行,那么doInBackground()方法、onPostExecute()方法在哪里执行呢?
………………省略好多源码………………
mWorker.mParams = params;
exec.execute(mFuture);
………………省略好多源码………………
上述代码解读:先把传入的参数对象params赋值mWorker持有的mParams持有,然后执行传入的exec的execute()方法,并且把mFuture传进去,后面已经没有别的源码了,说明doInBackground()方法、onPostExecute()方法一定跟这两行代码有关系!那么mWorker是什么?exec又是什么?mFuture又是什么?
3、还记得湖边的夏雨荷吗?在我们调用execute()方法时,它的内部会执行executeOnExecutor()方法时,还记得传递给executeOnExecutor()方法的第一个参数sDefaultExecutor吗?
sDefaultExecutor会赋值给executeOnExecutor方法内部的exec变量,sDefaultExecutor默认指向一个Executor对象,下方是它的初始化代码,最终sDefaultExecutor指向一个SerialExecutor对象,那么SerialExecutor对象又是什么?
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
4、SerialExecutor是AsyncTask类中定义的一个静态内部类,它实现了Executor接口,SerialExecutor具备作为Executor的能力
private static class SerialExecutor implements Executor {
………………省略好多源码………………
}
5、既然exec指向的是SerialExecutor对象,那么执行的execute()方法就是SerialExecutor对象的execute()方法
exec.execute(mFuture);
6、此时方法执行到这里(此时还在主线程执行),注意是SerialExecutor类中的execute()方法
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
mTasks是一个ArrayDeque对象(循环数组实现的双端队列),先调用mTasks的offer()方法向ArrayDeque对象中添加一个Runnable对象,注意:该Runnable对象中重写的run方法,在重写的run方法内部,即会调用传入的Runnable对象r的run方法,又一定会调用一个scheduleNext()方法
mActive是SerialExecutor对象持有的一个Runnable对象,当Active为null时,会调用一个scheduleNext()方法
7、scheduleNext()方法也定义在SerialExecutor类中,注意:该方法为同步方法,为了保证mActive、mTasks的线程安全,只有持有SerialExecutor对象锁的线程才能执行该方法
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
a、先从双端队列mTasks对象中取出一个Runnable对象并赋值给mActive,当mActive保存上Runnable对象后就会执行下面的逻辑
b、THREAD_POOL_EXECUTOR是AsyncTask类持有的一个线程池对象,在线程池对象中管理着多个工作线程,调用它的execute()方法,会将mActive对象放入到线程池中执行(由线程池中的工作线程执行)
8、线程池中的工作线程将调用Runnable对象中的run()方法,此时代码已经从主线程切换到工作线程中执行了
new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
}
这个Runnable对象就是在上面SerialExecutor类中mTasks中持有的Runnable对象,在该Runnable对象的run()方法内部:会调用r.run()方法,还记得r代表的是什么吗?
9、r是AysncTask对象持有的mFuture,所有此时mFuture的run()方法会被调用,我们知道mFuture是个FutureTask对象,mFuture是在AsyncTask的构造方法中初始化的!注意:以下代码位于AsyncTask类中的构造方法中!这时候r.run(),这个run方法在哪里?怎么没看到?创建FutureTask对象时传入的mWorker又是什么?
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);
}
}
};
10、r.run,调用的是FutureTask的run方法,你得进入FutureTask类中,才能看到这个run方法,注意:以下的run方法位于FutureTask类中
public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call(); //这里调用了Callable对象的call方法
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
没有看到doInBackground方法在哪被调用啊?是啊,因为使用了FutureTask对象,FutureTask对象创建时会接受一个Callbable对象或者Runnable对象,AsyncTask是怎么做的呢?AsyncTask是为mFuture传递了一个Callable对象,就是mWorker,那么mWorker是什么?
11、mWorker实现了Callable接口,他是在AsyncTask类的构造方法中初始化的,在FutureTask中的run方法中,Callable的call方法会被调用(见10号知识点的代码注释中),所以代码又走到了mWorker的call方法中
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
result = doInBackground(mParams); //doInBackground在这里被回调
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return result;
}
};
哇塞,我们终于看到了doInBackground()方法的调用(疑问1、疑问2的部分答案)…………证明它是在线程池中的某一个工作线程中执行的,此时我们还没有看到onPostExecute()方法的调用?那么onPostExecute()方法在哪被调用?
12、在mWorkder对象重写的call()方法中,还没看见onPostExecute()方法的调用,别着急继续往下看,我们发现在finally代码块中的postResult()方法非常可疑,难道onPostExecute()方法是在里面调用的吗?
13、仍然没有看到onPostExecute()方法调用,你想想Android的线程间通信用的什么?必须用Handler机制!
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
getHandler()方法会返回一个AsyncTask对象持有的Handler对象mHandler,它指向的是一个InternalHandler对象(见14号知识点),在调用Handler对象的obtainMessage方法时,传入的是第一参数是MESSAGE_POST_RESULT(它是AsyncTask类中定义的常量),另外一个参数是一个AsyncTaskResult对象(见17号知识点),Message对象的sendToTarget方法会经层层传递,将当前Mesage对象传到Handler对象的handleMessage方法中(见14号知识点),此时我们仍然没有看到onPostExecute方法的调用
private static final int MESSAGE_POST_RESULT = 0x1;
14、Message对象的sendToTarget方法,调用的是Message对象持有的Handler对象的send系列方法,最终Message对象又会回到Handler对象的handleMessage方法中,此时handleMessage方法已经切换到主线程中执行
在红圈处,AsyncTaskResult对象持有的mTask是什么呢?正是当前的AsyncTask对象(见17号知识点),我们去看看AsyncTask对象实现的finish方法(见15号知识点)
15、AsyncTask实现的finish()方法,在主线程中执行finish()方法
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
在finish方法中,如果AsyncTask没有被取消,就会在主线程中回调onPostExecute()方法(疑问1、疑问2的最后答案)哇,我们终于找到了onPostExecute方法被调用的地方
16、无参的getHandler()方法
private Handler getHandler() {
return mHandler;
}
返回AsyncTask对象持有的mHandler,它是自定义的一个Handler对象,与主线程相关的Handler对象,实际类型是InternalHandler
17、定义在AsyncTask类中的静态内部类
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
负责持有当前AsyncTask对象mTask、负责持有一个数组对象mData,
18、疑问3的答案呢?14号知识点的InternalHanlder的源码中的handleMesasge方法中还有一条MESSAGE_POST_PROGRESS消息的处理逻辑,这正是onProgressUpdate方法被调用的地方,那么是谁发出这个消息的?往下看!
19、在工作线程中执行的publishProgress方法
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
该方法的调用会发出一条MESSAGE_POST_PROGRESS的消息,此时在Handler对象中的handleMessage方法会被调用,你会看到onProgressUpdate方法的调用(见14号知识点)
总结
1、AsyncTask对象必须在主线程创建,因为AsyncTask内部使用Handler机制实现工作线程与主线程间的切换,这也是onPostExecute()、onProgressUpdate()在主线程被执行的原因
2、Executer接口,实现了该接口的类只是具备Executer能力,不能说为一个线程池,这里要注意,很多地方描述的并不准确
3、理解本文需要对Callable、FutureTask有所熟悉
4、默认的同一个进程中的所有AsyncTask对象提交的任务确实是串行执行的,任务是由线程池中的工作线程,执行完一个Runnable,才会再执行下一个Runnable(SerialExecutor对象持有的ArrayDeque对象mTasks负责持有任意一个AsyncTask对象提交的Runnable对象),不过如果能改变sDefaultExecutor的值就好了,可惜setDefaultExecutor方法是hide修饰的(此处不谈反射调用),这样我们就只能通过AsyncTask的executeOnExecutor()方法来改变AsyncTask执行任务的规则,把串行执行任务改变成并行执行任务
5、注意:本文源码基于API 28,其他版本的源码会有不同(我看API 29就改了部分实现方式)
/** @hide */
public static void setDefaultExecutor(Executor exec) {
sDefaultExecutor = exec;
}