AsyncTask介绍
AsyncTask是Android的一个异步类,监听异步任务的执行进度,通知主线程,耗时任务且主线程需要知道执行过程的场景下使用,比如进度条更新。消息通知模型采用线程池+Handler,异步任务结果获取采用FutureTask+Callable。
private static InternalHandler sHandler;
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());//绑定主线程Looper
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult> result = (AsyncTaskResult>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
InternalHandler类,静态内部类,主线程Looper绑定,主线程处理任务进度和结果,所有AsyncTask对象公用同一个静态Handler对象。
AsyncTaskResult类,封装AsyncTask对象,区分具体消息发送者。
AsyncTask是抽象类,AsyncTask
重写方法
doInBackground(Params…params):接受入参,耗时任务。
onPostExecute(Result result):处理结果。
选择重写方法
onProgressUpdate(Progress... values):主线程,消息处理,即进度更新。
onPreExecute():主线程,任务启动前执行。
onCancelled():主线程,用户取消时执行。
线程耗时任务。
protected abstract Result doInBackground(Params... params){
... //耗时任务
//同步进度到主线程
publishProgress(value);
}
publishProgress方法,通过InternalHandler类发送消息,实时发布进度。
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult
触发AsyncTask的#onProgressUpdate方法,更新进度,AsyncTask类通常会重写该方法。
任务完成,调用AsyncTask的postResult方法,通过InternalHandler类发送结果。
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult(this, result));
message.sendToTarget();
return result;
}
主线程AsyncTask的finish方法,调用重写的onPostExecute方法。
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result); //触发onCancelled空方法,子类可重写。
} else {
onPostExecute(result);// 子类重写。
}
mStatus = Status.FINISHED;
}
AsyncTask不清楚耗时操作产生的中间值做的事情,它只提供一个后台运行框架,中间值操作由使用者完成,子类实现。
基本原理
采用Callable+Future结构获取任务结果,AsyncTask的构造方法。
public AsyncTask(@Nullable Looper callbackLooper) {
//Handler绑定主线程Looper
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
mWorker = new WorkerRunnable() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
//结束call之前发送结果到主线程
postResult(result);
}
return result;
}
};
mFuture = new FutureTask(mWorker) {
@Override
protected void done() {
try {
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
} catch (ExecutionException e) {
} catch (CancellationException e) {//取消抛出异常,
postResultIfNotInvoked(null);
}
}
};
}
创建WorkerRunnable和FutureTask任务,WorkerRunnable是Callable类,和Runnable类似,执行主体是call方法,可以返回执行结果。
在call方法,调用doInBackground方法,做用户设定的耗时事情,将Result返回,最后,在finally代码块,postResult方法,发送消息通知结果,call方法结束。
FutureTask是Runnable类任务,实现Future接口,内部封装Callable任务,通过Future接口获取结果,重写done方法,处理结果。
创建AsyncTask对象,执行execute方法。
public final AsyncTask execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
调用executeOnExecutor方法。
@MainThread
public final AsyncTask executeOnExecutor(
Executor exec,Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
//抛异常
case FINISHED:
//抛异常
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
三种任务状态,PENDING是等待运行,RUNNING是运行中,FINISHED是完成,初始状态是PENDING。
任务开始,设置RUNNING状态,onPreExecute方法进行准备工作,(空方法,子类可选择重写),初始参数交给WorkerRunnable保存,push到线程池SerialExecutor的具体任务是FutureTask。
private static class SerialExecutor implements Executor {
final ArrayDeque mTasks = new ArrayDeque();
Runnable mActive;
public synchronized void execute(final Runnable r) {
//将Runnable加入队列,等待执行。
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
//当前mActive任务是空,说明还未取出过任务将其赋值。即当前没有任务执行。
if (mActive == null) {
scheduleNext();
}
}
//队列弹出任务,交给真正执行的线程池
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
任务队列ArrayDeque,将派发的FutureTask任务再次封装成一个新Runnable,投入队列,顺序执行。从队列取任务,交给真正的线程池。结束后,poll取下一个任务。
SerialExecutor功能是控制任务按顺序串行交给线程池。
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE,
KEEP_ALIVE,TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
3个核心线程(针对2个cup),最大线程数量是5,LinkedBlockingDeque(128)任务队列,任务是由SerialExecutor一次一个的顺序push的,当前任务完成,下一个任务创建新线程(<核心数量),线程数量达到核心数量,随机使用老线程处理。
注意
在Android2.3,API11前,直接采用5个线程的线程池,API11后,加入线程池SerialExecutor,变成串行。因此,可以加入判断,大于11时直接使用线程池THREAD_POOL_EXECUTOR,绕过SerialExecutor可避免串行。
任务
线程池THREAD_POOL_EXECUTOR处理任务,新Runnable的run方法,FutureTask的#run方法,触发Callable的call方法,即WorkerRunnable#call方法,最终,耗时操作是doInBackground方法。
private static final int NEW = 0;
private static final int COMPLETING = 1;
private static final int NORMAL = 2;
private static final int EXCEPTIONAL = 3;
private static final int CANCELLED = 4;
private static final int INTERRUPTING = 5;
private static final int INTERRUPTED = 6;
FutureTask有七种状态,新建,完成,普通,异常,取消和中断,前三种是正常状态,后四种是异常状态,执行过程触发状态变化。
public FutureTask(Callable callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW;
}
FutureTask构造方法,初始化NEW状态。
public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
Callable c = callable;
if (c != null && state == NEW) {//存在callable,执行其call方法
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
//成功标志
if (ran)
set(result);
}
} finally {
runner = null;
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
run方法,必须执行NEW状态的,若不是NEW或compareAndSwapXxx原子方法设置runner为当前线程(且初值需要是null)不成功,直接返回。
call方法,有两种执行情况,成功,状态情况NEW -> COMPLETING-> NORMAL。
protected void set(V v) {
if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
outcome = v;
U.putOrderedInt(this, STATE, NORMAL); // final state
finishCompletion();
}
}
set方法,设置结果,改变状态,finishCompletion方法,结束任务,outcome变量存储成功结果。
异常,状态情况NEW -> COMPLETING-> EXCEPTIONAL。
protected void setException(Throwable t) {
if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
outcome = t;
U.putOrderedInt(this, STATE, EXCEPTIONAL);
finishCompletion();
}
}
在catch代码块,setException方法,设置异常,改变状态,finishCompletion方法,结束任务,outcome变量存储异常Throwable。
private void finishCompletion() {
// assert state > COMPLETING;
for (WaitNode q; (q = waiters) != null;) {
if (U.compareAndSwapObject(this, WAITERS, q, null)) {
for (;;) {
Thread t = q.thread;
if (t != null) {
q.thread = null;
LockSupport.unpark(t);
}
WaitNode next = q.next;
if (next == null)
break;
q.next = null; // unlink to help gc
q = next;
}
break;
}
}
done();
callable = null; // to reduce footprint
}
异常或正常任务结束,利用LockSupport.unpark(Thread),唤醒在get方法处阻塞的线程,get方法情况适用于执行任务时,其他线程如主线程想通过FutureTask的#get方法获取任务结果,如果还未完成,阻塞,直到任务完成更新状态,通知唤醒,这里,此时还未执行get方法。
最后,done方法,FutureTask子类重写,利用get方法获取结果,传递给AsyncTask类的postResultIfNotInvoked方法。
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
在call方法,设置过mTaskInvoked标志,因此,向主线程postResult发送结果的消息不在done方法,在call方法的finally代码块。
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
get方法结果,状态<=COMPLETING,进行中,awaitDone方法陷入等待。状态>COMPLETING,完成,包括正常/异常,report结果。
private V report(int s) throws ExecutionException {
Object x = outcome;
//正常完成,返回结果
if (s == NORMAL)
return (V)x;
//取消异常,CANCELLED,INTERRUPTING,INTERRUPTED三种情况
if (s >= CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable)x);//中断异常
}
report两种情况,返回结果或抛出异常。异常在重写的done方法处被捕获。
当任务进行时,执行AsyncTask#cancel方法。
public final boolean cancel(boolean mayInterruptIfRunning) {
mCancelled.set(true);
return mFuture.cancel(mayInterruptIfRunning);
}
通过Future接口控制任务取消,改变AsyncTask的mCancelled标志位。
public boolean cancel(boolean mayInterruptIfRunning) {
if (!(state == NEW &&
U.compareAndSwapInt(this, STATE, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null)
t.interrupt();
} finally { // final state
U.putOrderedInt(this, STATE, INTERRUPTED);
}
}
} finally {
finishCompletion();
}
return true;
}
必须是执行中状态,非NEW状态。标志mayInterruptIfRunning,用户控制,cancel方法参数传入。
如果是中断任务,触发Thread#interrupt方法,线程并不会停止,继续运行,仅仅是改变了中断标志。
状态变化是NEW -> INTERRUPTING -> INTERRUPTED。
如果是取消任务,同样,线程继续执行。
状态变化是NEW -> CANCELLED。
最后,调用finishCompletion方法,进入done方法,这种情况下get方法结果时,状态是INTERRUPTED或CANCELLED,report方法会抛出CancellationException异常。在done方法,捕捉到CancellationException异常,执行postResultIfNotInvoked时,传入结果null。
耗时任务会继续执行,当call方法完成,postResult方法派送结果时,根据状态触发onCancelled方法,而不是onPostExecute方法。
注意
若用户在上层调用了AsyncTask的#cancel方法,主线程UI更新会停止,但是doInBackground执行不会停止,后台任务publishProgress时,会判断标志位mCancelled,已经在cancel方法设置,因此,不会再通知主线程进度。看不到UI更新了,以为线程被终止了,其实后台线程还在运行中。
总结
AsyncTask是一个可获取过程与结果的任务处理类,启动后,后台执行,进度更新(如果需要) ,结果处理,方法不需要亲自调用,只需要重写。
不一定由主线程创建AsyncTask ,因内部Handler已经自动绑定主线程Looper。
SerialExecutor的任务队列依次执行,也可以自己定义线程池。
任重而道远