时光荏苒,距离我上次写AsyncTask的文章已经过去快一年了
那个时候的我只get到了它的使用规律但是没有研究过源码,最近在强化自己对于源码的理解能力,所以对其源码进行了研究,如果对AsyncTask不熟悉的朋友可以看完我上面的博客再看这篇文章
我们一般使用AsyncTask的姿势如下:
new AsyncTask<String, Void, String>() {
@Override
protected String doInBackground(String... strings) {
return null;
//后台操作
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
//更新UI
}
}.execute("");
这两个回调方法是我们最熟悉的,或许大家还能记得
onPreExecute
onProgressUpdate
onCancelled
即使忘了也没关系,接下来我们分析源码的时候会带领大家重新认识这些方法
在开始這篇博客之前,需要提出几个问题?
1 AsyncTask实现原理是什么?
2 为什么AsyncTask只能在主线程创建(new AsyncTask)?
3 为什么说AsyncTask是串行执行?
接下来让我们看源码来分析这几个问题
首先是对象的创建(new AsyncTask),我们常用姿势就是创建一个匿名内部类(常常是无参的)
public AsyncTask() {
this((Looper) null);
}
这是一个重载方法,具体的实现在这里
-----code 1----
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
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);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return 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);
}
}
};
}
因为这段代码很重要所以我给他命名为”code 1”,之后还会再看这段代码,这里我们只需要了解无参构造方法传null,所以mHandler将会走getMainHandler()方法
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler(Looper.getMainLooper());
}
return sHandler;
}
}
InternalHandler是Handler的子类,这里面声明了一个InternalHandler类,sHandler是AsyncTask类的静态成员,所以AsyncTask在哪个线程创建,sHandler就属于哪个线程,因为方法参数已经规定是Looper.getMainLooper(),所以AsyncTask对象的创建必须在主线程,关于这个sHandler有什么用,我们等会再讲,先在这里埋下伏笔
接着源码执行的入口是execute方法
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
我们看到这里调用了executeOnExecutor方法并且传递了sDefaultExecutor参数,让我们看下sDefaultExecutor的样子
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
这个sDefaultExecutor是一个静态常量SerialExecutor,接下来看executeOnExecutor执行了什么
@MainThread
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;
}
每个AsyncTask都有一个执行的状态(即将开始,已经开始,已经结束),只有即将开始的任务才可以被执行,其余的都不可以,会抛出异常(这也是为什么AsyncTask只能调用execute一次的原因),这个时候我们看到了 onPreExecute()方法,没错!这个时候还没有启动线程所以可以用来做热身工作,紧接着调用了exec.execute(mFuture)也就是我们上面提到的SerialExecutor,它调用内部的execute方法,这个时候我们好奇的是这个mFuture是从哪里来的?
让我们把目光回到code 1,mFuture就是一个FutureTask,这个FutureTask的参数是mWorker,等FutureTask执行run方法就会回调mWorker的call方法,代码如下
//FutureTask类
public void run() {
result = c.call();
}
//WorkerRunnable
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);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return result;
}
};
这里出现了doInBackground方法,为我们在后台执行了耗时操作,执行完毕之后postResult方法把结果发送出来,因为这里的线程已经不是UI线程了,所以不能直接操作result,需要通过post传递出来,看到post你想到了什么?Handler!!没错!
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
使用了Message传递消息,既然有人传递就有人接受消息
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
@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;
}
}
}
果然我们前面提到的sHandler在这里派上了用场,用于收发消息,与此同时我们还能看到onProgressUpdate方法,这个就是我们开头提到的onProgressUpdate方法,既然拿到了结果走到了finish方法,那么看下finish方法有什么猫腻?
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
真相大白,原来onCancelled和onPostExecute都是在这里进行,二者只能取其一,所以如果一个任务被onCancelled了就不能走onPostExecute了
上述分析解释了整个异步任务的流程,但是有个问题一直悬而未决
FutureTask只是实现了Runnable接口,但是在哪里开启线程执行FutureTask()的?
刚才我们分析到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() {
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);
}
}
}
这个方法完美解释了AsyncTask串行执行的原理
ArrayDeque是一个双端队列,就是只能在头和尾进行插入删除操作,offer就是队尾插入一个元素,poll就是获取队头的元素并且删除这一个元素。因为SerialExecutor是静态类,所以mTasks和mActive是所有AsyncTask对象共享(所以方法前需要加synchronized,防止数据多线程操作之后变脏)。
无论多少个AsyncTask被执行但是都会按照先后顺序从队尾添加到ArrayDeque,起初mActive为空,所以直接进入scheduleNext方法,这个方法是执行队列的头元素(执行头元素的run方法,再执行scheduleNext方法如此循环)直到所有的元素都执行完保证所有的run方法按照顺序执行
如果第一遍咩有理解这句话,希望大家多读几遍,多理解一下,下面配张图希望能帮助大家理解下
先执行1,再执行2,2中执行3中头元素的run方法再继续执行2方法,如此循环直到队列中不存在头元素,这就是AsyncTask的串行执行原理
你可能现在还有疑问,我还是没有看到任何一个Thread啊!难道不是用Thread.start?
这个时候要说说我们本场的重量级嘉宾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;
}
没错,虽然你不一定知道这是什么东西,但是这个ThreadPoolExecutor你一定见过,足以可见其牛逼程度了,这是一个线程池调度器,几乎所有的线程相关都有他,在这里不深入讲,只知道他的作用即可,后面写博客的时候会详细讲ThreadPoolExecutor的源码
维持有限数量的线程池,通过复用线程提高效率
public void execute(Runnable command) {
//其他省略
addWorker(command, true)
}
private boolean addWorker(Runnable firstTask, boolean core) {
//省略
final Thread t = w.thread;
if (workerAdded) {
t.start();
workerStarted = true;
}
}
至此,AsynTask就全部分析完毕了,感谢各位朋友能坚持读到现在,如果有什么不懂得地方欢迎指出,希望一起进步,一起努力~