转载注明出处:http://www.jianshu.com/p/26e1f7be4d0d
简介
上一篇主要针对AsyncTask
内部使用到的一些线程的技术进行了基本的讲解,如果还没有看过的同学,可以点开这个AsyncTask 第二篇线程篇去查看一下。这一篇就从源代码分析AsyncTask
的具体实现,也终于从第一篇的使用到了实现的思路。下面就直接开始了。
方法调度说明
在AsyncTask
里面其实我们最关心里面实现的思路了,这就需要结合一下AsyncTask
怎么使用,才更方便的理解内部的实现,如果还有同学并不了解它的使用,可以查看AsyncTask 第一篇使用篇这篇文章。
所有的开始都是从调用AsyncTask.execute(params)
方法,我们直接看一下这个方法吧。
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
在execute(params)
内部直接调用了executeOnExecutor
方法,并将一个Executor
的实例化对象传入,同时也将运行参数传入,我们来看一下executorOnExecutor
方法吧。
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.execute(params)
方法后,紧接着就会调用onPreExecute()
方法,这个方法我们可以复写,并做一些任务执行前的一些操作。
在这个方法里面,首先会对自身状态进行判断,如果是RUNNING
和FINISHED
状态就会抛出异常,也就是前面提示的每一个实例化的AsyncTask
只能执行一次,如果执行多次会抛出异常。判断完毕后,将自身状态设置为RUNNING
状态,并调用onPreExecute()
方法,接着将参数传入mWorker
中,执行mFuture
,那说明mFuture
即可以作为线程运行的结果,也可以作为一个线程执行的任务,根据上一篇关于线程的文章,我们就可以大胆猜测,mWorker
实现了Callable
接口,而mFuture
其实是一个FutureTask
的实例化对象。
赶紧找到mWorker
的声明。
private final WorkerRunnable<Params, Result> mWorker;
......
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
找到声明处,紧接着找到了具体的类,果然和我们猜测一样,mWorker
实现了Callable
接口,但是只是一个抽象类,里面声明了一个泛型的成员变量,没有call()
具体实现,我们直接去找mWorker
实例化的地方,看一下call()
方法的具体实现。
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
构造函数里面就会对mWorker
和mFuture
实例化,在mWorker
对象中的call()
方法里面,先设置了线程优先级,然后调用了我们熟悉的方法doInBackground()
,并获取了运行的结果,调用了postResult()
方法将结果传入。mFuture
实例化的类获取了mWorkder
实例化对象,并复写了done()
这个方法,很容易理解这个done()
方法是线程具体任务执行完毕后调用的,复写done()
方法主要是保证获取到执行结果,我们看一下postResultIfNotInvoked()
这个方法就明白了。
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
在这个方法里面,也会将执行结果传入postResult()
方法。
在这里我们看见了两个比较熟悉的方法,一个是doInBackground()
一个是postResult()
,我们先来看doInBackground()
吧。
protected abstract Result doInBackground(Params... params);
是一个抽象方法,也就是说我们在继承或者直接实例化实时必须实现她。
再来看一下postResult()
。
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
将执行结果通过Handler传入了UI线程中的某个方法,想必大家都猜到了最终会调用到onPostExecute(Result result)
,但是目前为止我们只是获得了运行的结果,但是并没有获取到在执行过程中的执行状态。去看一看publishProgress
一探究竟。
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
原来这个方法也是将用户传入的执行状态直接通过Handler传到UI线程的某个方法,对,就是onProgressUpdate
方法。可以看见最关键的两个异步消息的处理,结果和执行状态信息都是通过Handler传到UI线程,直接看一下Handler的声明。
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
@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里面就处理了两类消息,一个是抛出运行结果消息,一个是抛出运行状态的消息。如果是运行状态,直接回调用AsyncTask
的onProgressUpdate
方法,和大家猜想是一样的。如果是运行结果,会调用finish
方法,我们看看这个方法,为什么不是直接调用onPostExecute
方法。
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
很明显,如果在执行过程中,用户没有去取消,就会调用onPostExecute
方法,如果取消了就会调用onCancelled
方法。然后最终,会将AsyncTask
的执行状态变为FINISHED
状态,一旦置为这个状态,再去调用AsyncTask.execute(params)
就会抛出异常,这个在调用该方法时候就会去判断,大家可以去上面看一下这块源代码。
到目前为止,AsyncTask
内部方法间的调度顺序大家通过源代码想必有了大体的认识。但是如果现在让大家自己写一个类似的类DemoTask,大家会怎么实现?根据上一篇的文章,我们会直接实例化一个Executor去执行FutureTask,并使用Handler来处理异步线程间通信。这样是正确的做法,但是一旦当我们自定义的DemoTask被大量时候的时候,我们并不能对它有一个统一的管理,所以我们有必要看一下官方对于这一块是怎么处理的。
线程调度说明
大家记得在调用AsyncTask.execute()
方法时候,会有一个sDefaultExecutor
实例化对象出现过吧,很明显,它是用来执行FutureTask
的,而且是个常量,直接去看一下它的定义。
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);
}
}
}
代码很容易理解,它在执行时候会将FutureTask
放入一个匿名Runnable
的执行方法中,然后将这个匿名Runnable
添加到自身一个成员变量,如果首次调用这个方法,会执行调用scheduleNext
方法,使用线程池去运行这个匿名的Runnable
。如果当前匿名Runnable
中的FutureTask
执行完毕,也会调用ScheduleNext
方法。
我们来看一下线程池THREAD_POOL_EXECUTOR
声明的地方。
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE,
MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS,
sPoolWorkQueue,
sThreadFactory);
前面这些常量通过字面含义就能大体了解含义了,如果有同学想知道具体含义,可以去查看一下源代码,我们现在仅看一下sPoolWorkQueue
这个参数。
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
很明显,它是一个用来存储线程池中线程的队列,而且最多能容纳128个线程。而且由于这个线程池是全局的一个静态常量,所以在一个进程中所有我们实例化AsyncTask
的具体执行任务都会被添加到这个线程池中。
至此关于AsyncTask
中线程的调度,也有了一个清晰的脉络。
总结
虽然AsyncTask
是一个快过时的类,而且它不适合执行长时间后台操作,但是在许多场景我们依然会需要到它,而且通过源代码,我们可以对这种作者的思路做出一个很好的总结,对Handler的使用场景和使用方法,有了更深的认识。至此,我们也可以参考AsyncTask
的思路,自定制适合自己的异步消息处理的机制。