在平常开发中执行异步操作很常见的操作,经常在执行异步任务后需要去刷新 UI,这就需要用到 Android 的异步消息处理机制 Handler, 当然我们也可以使用 AsyncTask 去完成,相信大家或多或少都用过 AsyncTask 。
基本用法:
三个泛型 : AsyncTask < Params, Progress, Result >
1. Params : 启动任务执行传入的参数, 例如HTTP请求的URL , 执行任务需要的数据类型
2. Progress : 后台执行任务进度的进度类型
3. Result : 异步任务最终返回的结果类型
几个常用方法:
protected void onPreExecute() {}
- 执行在UI线程, 一般在执行异步任务前做一些UI操作
protected Result doInBackground(Params … params) {}
- 执行在异步线程, 耗时的操作在这个方法中执行。 返回结果被传递到 onPostExecute(), 在执行任务时调用publishProgress() 把执行进度传递给 onProgressUpdate()
protected void onProgressUpdate(Progress … progresses) {}
- 执行在UI线程, 更新进度信息, 调用 publishProgress() 时被回调
protected void onPostExecute(Result result) {}
- 执行在UI线程, 一般在执行完后台任务后更新UI的操作, 显示结果等
protected void onCancelled() {}
- 执行在UI线程, 调用 cancel() 被调用
源码流程
具体用法就不再这里展示了,接下来我们直接看源码,首先看 new AsyncTask() 时候构造方法里面做了什么:
构造方法
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
...省略
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
...省库
}
};
}
2 行:
mWorker
是WorkerRunnable
类型的内部类对象:
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
分析继承关系,最终 WorkerRunnable
实现了 Callable
接口,接口中只有一个 call()
方法返回值类型是泛型。因为不论是继承 Thread 类还是实现 Runnable 方法,执行完任务以后都无法直接返回结果。而Callable
接口弥补了这个缺陷,当call()
方法执行完毕以后会返回一个泛型对象。mWorker
重写了 call
方法,具体实现先不看,等调用的时候再具体分析
接着第 8 行:
FutureTask
,它实现了RunnableFuture
接口,RunnableFuture
最终继承Runnable
和Future
接口
public interface RunnableFuture<V> extends Runnable, Future<V> {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}
Runnable
接口我们熟悉, 说明 FutureTask
是可以被 Thread 执行的, Future<V>
接口主要是针对Runnable 和 Callable 任务的。提供了三种功能:
- 判断任务是否完成 ;
- 中断任务 ;
- 获取任务执行的结果
mAsyncTask().execute();
接着我们从执行异步任务的起点开始,进入 execute 方法:
##mAsyncTask
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
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;
}
5行:判断任务在运行当中或者已经执行完成, 则报出异常,即每个任务只能执行一次
17行:执行了 onPreExecute() , 当前还在主线程
18行:用 mWorker.mParams 保存传入的参数
19行:调用参数 Executor 类型的 exec 的 execute() 方法, 并把 mFuture 传进去,exec 是在 execute() 方法中传的 sDefaultExecutor。
sDefaultExecutor
是 SerialExecutor 类的实例, SerialExecutor 内部维护了一个 ArrayDeque
类型的队列 mTasks
##mAsyncTask
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
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);
}
}
}
7-12 行:封装传入进来的
mTask
添加到mTasks
队尾,可以看到在run()
方法中,执行mTask
的run()
方法后一定会执行scheduleNext()
16-17 行:判断 Runnable 类型的mActive
是否为空,第一次执行肯定为空,则调用scheduleNext()
21-22 行:取出队首的元素赋给mActive
,不为空则让线程池去执行这个任务
- 从上面可以分析出来,当队列中有任务时,任务的执行顺序是当队列中前一个任务执行完成后,后面如果有任务则继续取出并让
THREAD_POOL_EXECUTOR
线程池去执行,执行完成后继续队列中的后一个任务,知道队列中没有元素为止。而重复执行AsynscTask.execute()
并不会多次触发线程池,只有队列中没有任务时,才会触发线程池执行添加进来的任务。所以,安卓7.0下的AsyncTask
任务执行是串行的,相当于单线程池的效果。
我们继续看任务的执行,即线程池去执行 mTask
的 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();
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);
}
}
6 行:
callable
就是 FutureTask 构造方法中传入进来的mWorker
,然后赋值给c
11 行:执行 mWorker 的call()
方法,并得到执行结果result
, 而 mWorkder 在 AynscTask 构造方法中重写了 call() 方法
##AsyncTask
public AsyncTask() {
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) {...}
}
4 行:标记位
mTaskInvoked
设置为 true
7 行:设置线程优先级 为10。优先级分为 1-10,数值越大优先级越高,默认是5。
9 行:出现了doInBackground()
, 此时方法调用在 mTask 的 run() 中,即在异步线程中执行 doInBackground() 并得到返回结果 result
15 行:postResult(result)
,字面意思是把结果 post 出去。方法实现先不看,因为后面也调用了此方法再具体分析
继续看 FutureTask run() 方法的 19 行:set(result)
##FutureTask
protected void set(V v) {
if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
outcome = v;
U.putOrderedInt(this, STATE, NORMAL);
finishCompletion();
}
}
3 行:用
outcome
保存执行结果
5 行的 finishCompletion():
##FutureTask
private void finishCompletion() {
// assert state > COMPLETING;
for (WaitNode q; (q = waiters) != null;) {
if (U.compareAndSwapObject(this, WAITERS, q,
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
}
直接看倒数第二行
done()
方法,是不是很眼熟?还记得 AsyncTask 构造方法中 mTask 重写了 done() 方法吗
##AsyncTask
public AsyncTask() {
mWorker = new WorkerRunnable<Params, 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);
}
}
};
}
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
在 mTask 重写的 done()
方法中, 把 get() 获取的任务执行结果传递给 postResultIfNotInvoked()
方法,在方法中:如果 mTaskInvoked 不为true,则执行 postResult
; 但是在 mWorker 初始化时就已经 将 mTaskInvoked 为 true,所以一般这个 postResult 执行不到。所以这个 postResult 一般是在 mWorker 执行结束 call() 时执行
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
可以看到 postResult 中出现了我们熟悉的 Handler 消息机制,传递了一个消息 message, message.what = MESSAGE_POST_RESULT;message.object = new AsyncTaskResult(this,result);
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
AsyncTaskResult 就是对 AsyncTask 和 result 数据的简单封装。
很容易猜测出来 sHandler 肯定重写了 handleMessage() 方法去接收这个消息并处理:
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
@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;
}
}
}
3 行:说明是主线程的 Handler
9 行:msg.what 分两种 MESSAGE_POST_RESULT 和 MESSAGE_POST_PROGRESS,即结果 result 和 进度progress,这里先看 result 的处理
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
如果任务被 cancel() 则调用
onCancelled()
,正常执行完调用onPostExecute()
,此时在 Handler 的handleMessage
中,因此是主线程执行,最后将状态置为 FINISHED
在日常开发中一个常用操作就是在 doInBackgroud 中调用 publishProgress
把执行进度更新给 onProgressUpdate
,然后在 onProgressUpdate 根据执行进度来做一些 UI 处理,比如显示进度条之类的:
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
还是通过 sHandler 发送一个 message , what 是 MESSAGE_POST_PROGRESS
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 的 handleMessage 中,回调了
onProgressUpdate
,明显执行在主线程
到这里,整个 AsyncTask 的执行流程就结束了,看起来好像方法东跳来西跳去有点晕,其实自己对着源码多走几遍就很清晰了
下面有个比较清晰的流程图,借用自 (https://www.jianshu.com/p/e60c3bb03d61)
cancel()
此外,在 AsyncTask 中有一个小坑要注意一下,对于 cancel 方法的调用:
* @param mayInterruptIfRunning <tt>true</tt> if the thread executing this
* task should be interrupted; otherwise, in-progress tasks are allowed
* to complete.
*/
public final boolean cancel(boolean mayInterruptIfRunning) {
mCancelled.set(true); // 标志位 mCancelled 设置为 true
return mFuture.cancel(mayInterruptIfRunning);
}
从官方注释来看,mayInterruptIfRunning
如果为 true 当前异步任务就会被终止,否则该任务会执行完成。而实际开发中,调用 cancel 并不能中断当前执行的任务。
通过源码可以看到,方法内部只是给 AsyncTask 设置一个 “
canceled
” 状态,然后向运行中的线程发出interrupt()
调用。在这种情况下,你的线程是不可中断的,也就不会终止该线程。所以,这就需要你主动去检查 AsyncTask 是否已经取消,之后决定是否终止你的操作。因此需要这样操作
public void onProgressUpdate(Integer... value) {
...
if(isCancelled())
return;
...
}
@Override
protected Integer doInBackground(Void... mgs) {
...
if(isCancelled())
return null;
...
}
...`
另外在需要结束 AsyncTask 的地方:
if(task != null && !task.isCancelled() && task.getStatus() == AsyncTask.Status.RUNNING) {
task.cancel(true);
task = null;
}