AsyncTask是Android提供的一个工具,可以用来处理轻量级的异步任务,AsyncTask是一个非常经典的模板模式的实现,模板模式:大概就是说,执行一次exeute,可以依次执行一些可以被你重写的方法。就像AsyncTask,每次执行exeute,都会依次执行onPreExecute,doInBackground,onPostExecute,这三个方法只有doInBackground会在异步执行,onPostExecute会在主线程执行,同时在异步执行的过程中,可以选择性地执行onProgressUpdate,来告诉主线程,后台已经执行到了那个步骤。
使用方法
看一下这个类定定义:
public abstract class AsyncTask<Params, Progress, Result>
可以看到这时一个抽象类,同时通过泛型编程的方式可以定义三个参数Params, Progress, Result,分别对应着可以传入doInBackground,onProgressUpdate,onPostExecute的参数,Result同时也是doInBackground的返回值
protected abstract Result doInBackground(Params... params);
protected void onProgressUpdate(Progress... values) {
}
protected void onPostExecute(Result result) {
}
同时也可以看到doInBackground是一个抽象方法,使用时必须实现它,而其他的则是可选的。
简单使用
new AsyncTask<String, Void, JSONObject>() {
@Override
protected JSONObject doInBackground(String... params) {
return getContactsByPhoneNumber(resolver, params[0]);
}
@Override
protected void onPostExecute(JSONObject result) {
request.getCallback().callback(new Response(Response.CODE_SUCCESS, result));
}
}.execute(phoneNumber);
这个例子也是非常简单,主要也是可以看一下各个参数间的关系,它可以在主线程和后台线程之间传递一些对象。
线程池
既然要后台线程执行,那必不可少的就是线程了,AsyncTask就有两个或者说是一个线程池,通过static的方式,保证一个进程内只有一份。
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
/**
* An {@link Executor} that executes tasks one at a time in serial
* order. This serialization is global to a particular process.
*/
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();
}
}
});
// 将runable加入到队列当中
if (mActive == null) {
//如果mActive为空,则执行下一个runable
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
// mActive为runable的第一个,并且只用THREAD_POOL_EXECUTOR执行它。
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
通过看SerialExecutor的定义发现,它其实是THREAD_POOL_EXECUTOR的封装,实际使用的还是THREAD_POOL_EXECUTOR,并且可以看到它维护了一个Runable的队列,真正在执行的Runable只有一个。也就是说使用SERIAL_EXECUTOR其实就是一个单线程池
再来看THREAD_POOL_EXECUTOR
/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
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;
}
这时一个真的线程池了,具体的就不解释了。其实在默认情况下都是使用的sDefaultExecutor,所以在你不指定线程池的情况下,你就把他当做一个单线程池来用,同时需要注意的是在一个进程内,这个线程池都是这一个,这意味这你要小心,你的异步任务可能都在排队,所以这个只适用于轻量级的任务,你要保证后台的任务不会花太长的时间,也不能有阻塞的风险,不然的话就会导致其他任务的延后或者阻塞。
执行过程
接下来看看exeute
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
// 根据注释,这个方法必须在UI线程执行,也可以看到就是用的sDefaultExecutor,
// 同时不知道为何,既然只能在UI线程执行为何sDefaultExecutor 声明为了volatile,
// 这是我的一个疑问吧。
@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)");
}
}
// 在执行前,状态必须是Status.PENDING,
mStatus = Status.RUNNING;
onPreExecute();
// 执行onPreExecute()
mWorker.mParams = params;
// 赋值params
exec.execute(mFuture);
用线程池执行mFuture
return this;
}
这个mFuture和mWorker到底是什么的,应该很容易猜到 Callable和FutureTask
private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
private final AtomicBoolean mCancelled = new AtomicBoolean();
private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
// 两个AtomicBoolean,保证线程安全,代表任务是否取消,后台任务是否执行了
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
// 可以看到返回值是Result,FutureTask的get()方法可以得到,防止因意外不执行
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);
// 会将结果post到主线程
}
return result;
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
// 重写了done方法,就是说如果一些原因,后台线程线程没能执行,我们也要postResultIfNotInvoked
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) {
// 如果WorkerRunnable未能执行
postResult(result);
}
}
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
// 可以看到,postResult,就是向这个Handler发送一个messge,这应该是android线程间交互的最简单的方式之一,这样我们就能吧result发回到主线程。
最后看看这个handler
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:
// There is only one result
result.mTask.finish(result.mData[0]);
// 调用finsih
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
// 如果已经cancel,调用onCancelled() 一个可重写方法
} else {
onPostExecute(result);
// finish后onPostExecute
}
mStatus = Status.FINISHED;
}
// 可以看到它还处理一个message:MESSAGE_POST_PROGRESS, 可以猜到了就是那个onProgressUpdate。
// 我们只需要在doBackground中执行publishProgress
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
// 这样就可以把一些中间过程post到UI线程
到这里AsyncTask的原理就差不多介绍完了,还有小细节就不多说了,它其实就是用了FutureTask来执行后台任务,并且通过一个handler来实现与主线程的交互,可以看到整个源码也是非常的少,调用过程非常清晰而且容易理解。