一,前言
今日在使用AsyncTask时,发现对其实现原理又不太记得了,在此再解读一边,以便记忆和使用。
android3.0前的多线程并行执行的版本年代久远就不再分析了,
二,使用
1.场景
在使用一个Thread处理事务,然后使用Handle在UI线程接收处理结果进行后续工作。简单来说就是替代Thread + Handler 的一种方式。
这是我第一次使用AsyncTask的状态,用以实现新线程后台操作和UI更新。如网络请求和数据库操作等都会用到AsyncTask。
但AsyncTask的后台操作耗时也不应该太长,耗时操作还是要使用并发库中的工具类。
2.参数和方法
2.1 参数
private class Test extends AsyncTask<Params, Progress, Result> { ... }
我们继承AsyncTask时,会有三个参数Params, Progress, Result要定义。
- Params:AsyncTask执行时的输入到doInBackground参数的类型;
- Progress: 后台执行任务时,计算出的完成进度onProgressUpdate的数值类型;
- Result: AsyncTask的doInBackground执行完毕后onPostExecute的返回类型
2.2 方法
- onPreExecute:在执行后台任务前,会先调用这个方法用于准备工作。
- doInBackground:在执行完onPreExecute后,将会执行doInBackground接口来完成后台耗时工作,execute参数的值将会传入这里成为它的参数。在doInBackground中可以调用publishProgress接口更新进度条,
进度条的数值将通过onProgressUpdate接口更新到UI界面。doInBackground的返回结果将交予onPostExecute在UI线程处理。 - onPostExecute:方法参数为doInBackground的返回值,在UI线程中执行。
- onCancelled:和onPostExecute一样,在doInBackground执行完之后在UI线程中执行。但是在执行cancel后才会调用,此时不会再调用onPostExecute方法了。为了尽快响应cancel,doInBackground中应检测isCancelled的返回值。
2.3 注意事项
- AsyncTask的创建和使用必须在主线程中。
- 每个AsyncTask对象都只能执行一次。
- 为了线程安全,doInBackground使用的成员变量必须在初始化在构造函数或onPreExecute中,在doInBackground中初始化的的变量,由onProgressUpdate和onPostExecute使用。
- AsyncTask默认在一个线程中按插入顺序执行,要多线程并发要调用executeOnExecutor方法传入线程。
三.解析
解析方式,就从execute方法一步一步走下去。
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
executeOnExecutor则是指定线程执行的方法,可以看出execute是使用默认线程sDefaultExecutor执行后台任务。
3.1 sDefaultExecutor
下面来看看sDefaultExecutor是怎样的,它从表面上看是默认的Executor
//静态成员变量,类共享
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
//静态内部类,类共享为顺序执行提供便利
private static class SerialExecutor implements Executor {
//mTasks用于保存任务,没执行一次execute插入一条,scheduleNext去除一条
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
//正在执行的任务
Runnable mActive;
public synchronized void execute(final Runnable r) {
//插入任务,被插入的任务将会迭代执行。
mTasks.offer(new Runnable() {
public void run() {
try {//先执行Runnable
r.run();
} finally { //再条用scheduleNext执行下一个任务。
scheduleNext();
}
}
});
//如果当前没有正在执行的任务,调用scheduleNext取出任务执行
if (mActive == null) {
scheduleNext();
}
}
//如果队列有任务,则取交予THREAD_POOL_EXECUTOR执行
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
对ArrayDeque任务队列的取出,是先进先出的策略,每执行一次execute就是插入mTasks队列一个迭代任务,然后判断当前有无正在执行的任务,确保顺序执行。
SerialExecutor是实现顺序执行功能的,真正执行任务的是THREAD_POOL_EXECUTOR线程池。
THREAD_POOL_EXECUTOR的参数就不再分析了,因为SerialExecutor使其相当于单线程在使用,线程池的并发也就派不上
用场了。
3.2 executeOnExecutor
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
//对象创建时默认为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.mParams
mWorker.mParams = params;
//默认情况下将mFuture交予上面的sDefaultExecutor执行
exec.execute(mFuture);
return this;
}
onPreExecute在这里最早被执行了,接着sDefaultExecutor开始执行。
那mFuture和mWorker又是什么呢?从params上看doInBackground和mWorker有关,从execute上看doInBackground又和mFuture有关。可以猜测doInBackground在mWorker中调用,而mWorker又在mFuture中调用。
3.3 mFuture和mWorker
还是从exec.execute(mFuture)开始,execute是需要Runnable对象,Runnable接口只有个run,用来执行业务。
public void run() {
....
try {
//Callable就为mWorker对象
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
//执行了mWorker对象的call方法
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
//调用了finishCompletion方法
set(result);
}
} finally {
....
}
}
/**
* Removes and signals all waiting threads, invokes done(), and
* nulls out callable.
*/
private void finishCompletion() {
// assert state > COMPLETING;
....
done();//在新建mFuture,覆盖了这个方法
//置空mWorker的引用
callable = null; // to reduce footprint
}
在run方法中,执行了callable.call方法,执行成功后又调用了done方法。下面就来介绍call和done方法的实现。
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
//将会在FutureTask的run方法中执行
public Result call() throws Exception {
//设置标志位,设置为true后,mFuture中将不会再次调用postResult
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//doInBackground在此处被调用
return postResult(doInBackground(mParams));
}
};
//在创建对象时,传入mWorker作为callable参数,在run中被调用
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 occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
//当mWorker的call方法被调用后,postResult将不会被调用
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
由上可知执行顺序:FutureTask.run -> WorkerRunnable.call -> doInBackground -> FutureTask.done。
对于doInBackground的返回结果,则是由postResult处理。
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
private static class InternalHandler extends Handler {
@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;
}
}
}
//处理返回结果
private void finish(Result result) {
//如果调用了cancel,则接下来调用onCancelled,否则onPostExecute
if (isCancelled()) {
onCancelled(result);//调用了onCancelled方法
} else {
onPostExecute(result); //onPostExecute在此处调用
}
mStatus = Status.FINISHED;//修改标识
}
处理结果通过InternalHandler,最后调用了finish方法来处理,而finish方法根据是否调用cancel来决定调用onCancelled还是onPostExecute。
这里封装了一个AsyncTaskResult类来传递结果,原因很简单,handler是静态对象,没法直接拿到当前MyAsyncTask的引用。而我们要把task和result对象同时丢给handler,所以要进行一下封装。
3.4 onProgressUpdate
在上面的InternalHandler中,当接收消息为MESSAGE_POST_PROGRESS时,将会调用onProgressUpdate来更新进度。
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
而这个方法是由publishProgress来发送的。所以在doInBackground中,需要手动调用publishProgress方法来更新进度。
3.5 cancel
前面说到cancel,会影响onCancelled和onPostExecute的调用。它还会影响FutureTask执行的任务。
public final boolean cancel(boolean mayInterruptIfRunning) {
mCancelled.set(true);
//FutureTask将会执行cancel,根据mayInterruptIfRunning来决定是否立即停止这个任务
return mFuture.cancel(mayInterruptIfRunning);
}
//FutureTask
public boolean cancel(boolean mayInterruptIfRunning) {
....
try { // in case call to interrupt throws exception
//如果为false,则不会停止正在执行的任务
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null)
t.interrupt();//停止正在执行的任务
} finally { // final state
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
}
}
} finally {
//回调FutureTask的done方法
finishCompletion();
}
return true;
}
mayInterruptIfRunning为true,FutureTask会告诉线程停止执行这个任务,否则不会停止线程继续执行。
随后执行finishCompletion,而finishCompletion方法中会调用done方法,再清空callable也就是WorkerRunnable对象。
上面分析mWorker的代码中讲过,mFuture.done中执行的postResult,是由mWorker的call方法是否执行决定决定的。如果任务正在执行,则由WorkerRunnable的call方法发送消息执行onCancelled,否则由FutureTask的done发动消息执行onCancelled。
也就是说,mFuture.done方法发送消息,只能是执行cancel且要取消的任务还在队列中。
四 总结
总结下普通的一个执行流程:execute(Params... params) -> executeOnExecutor(sDefaultExecutor, params) -> onPreExecute() -> sDefaultExecutor.execute(mFuture) -> scheduleNext() -> THREAD_POOL_EXECUTOR.execute(mActive) -> FutureTask.run() -> WorkerRunnable.call() -> postResult(doInBackground(mParams)) -> result.mTask.finish(result.mData[0]) -> onPostExecute(result)
我做了个简单的时序图:https://www.processon.com/view/link/5a717790e4b0874437b31e97
其中在FutureTask中
FutureTask.run() -> WorkerRunnable.call() ->
FutureTask.set(V v) -> FutureTask.finishCompletion() -> FutureTask.done() -> AsyncTask.postResultIfNotInvoked(Result result) -> postResult(Result result) -> onCancelled(result);
用流程图或UML画图更直观展示,以后有机会再补充。
网友评论