简介
AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
主要是为了在后台线程中做操作时更新 UI 的
AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent package such as Executor, ThreadPoolExecutor and FutureTask.
封装了 Thread 和 Handler,AsyncTask最好做短时的操作(最多几秒),如果需要做长时间的活 建议使用 ThreadPoolExecutor,Executor,Executor
An asynchronous task is defined by a computation that runs on a background thread and whose result is published on the UI thread. An asynchronous task is defined by 3 generic types, called Params, Progress and Result, and 4 steps, called onPreExecute, doInBackground, onProgressUpdate and onPostExecute.
异步的任务在后台执行,结果被在传到 UI线程。异步任务分为三个部分 Params,Progress,Result和4个步骤onPreExecute, doInBackground, onProgressUpdate and onPostExecute
使用
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
//工作线程
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
//
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
//UI 线程
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
//结果回调
showDialog("Downloaded " + result + " bytes");
}
//UI 线程,在doInBackground 之前被调用,做一些初始化的工作
protected void onPreExecute(){
}
}
new DownloadFilesTask().execute(url1, url2, url3);
源码分析
构造函数
以下源码分析基于 API23
//首先看看构造函数
/**
* 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 {
mTaskInvoked.set(true);
//设置了优先级
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
//调用了后台的回调方法
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
//将结果发送到回调
return postResult(result);
}
};
// FutureTask的构造参数需要一个 Callable
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);
}
}
};
}
构造函数初始化了两个变量mWorker
,mFuture
private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
//是一个 Callable
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
//内部定义了春哥AsyncTaskResult 内部类
@SuppressWarnings({"RawUseOfParameterizedType"})
private static class AsyncTaskResult<Data> {
//注意这里有两个成员变量,AsyncTask是方便在 hanlder 的 handleMessage 回调
//中方便调用 AsyncTask本身的回调函数,如 onPostExecute ,onPreogressUpdata,
//所有在AsyncTaskResult 需要持有 AsyncTask。
//而Data 就是泛型的结果了
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
postResult
具体看看是如何 postResult的
// 通过hanlder 机智发送了一个 message
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
// 这里的AsyncTaskResul 是 WorkerRunnable的一个内部类
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
//hanlder 是一个单例
private static Handler getHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler();
}
return sHandler;
}
}
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
//AsyncTaskResult 中的 task 是一个AsyncTask,调用了 AsyncTask 的 finsh 方法,在 finish 方法这 回调了用户的回调函数 onPostExecute(result)
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
//进度消息
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
//同样publishProgress 也是通过 handler 发送 message 的方式
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
execute
@MainThread
public static void execute(Runnable runnable) {
sDefaultExecutor.execute(runnable);
}
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();
//默认为串行任务的Executor
private static class SerialExecutor implements Executor {
//任务队列
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
//接受一个 Runnable 参数,对应的是FutureTask成员变量
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 来执行任务。FutureTask 是用来做排队的
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
分析
SerialExecutor是使用ArrayDeque这个队列来管理Runnable对象的,如果我们一次性启动了很多个任务,首先在第一次运行execute()方法的时候,会调用ArrayDeque的offer()方法将传入的Runnable对象添加到队列的尾部,然后判断mActive对象是不是等于null,第一次运行当然是等于null了,于是会调用scheduleNext()方法。在这个方法中会从队列的头部取值,并赋值给mActive对象,然后调用THREAD_POOL_EXECUTOR去执行取出的取出的Runnable对象。之后如何又有新的任务被执行,同样还会调用offer()方法将传入的Runnable添加到队列的尾部,但是再去给mActive对象做非空检查的时候就会发现mActive对象已经不再是null了,于是就不会再调用scheduleNext()方法。
那么后面添加的任务岂不是永远得不到处理了?当然不是,看一看offer()方法里传入的Runnable匿名类,这里使用了一个try finally代码块,并在finally中调用了scheduleNext()方法,保证无论发生什么情况,这个方法都会被调用。也就是说,每次当一个任务执行完毕后,下一个任务才会得到执行,SerialExecutor模仿的是单一线程池的效果,如果我们快速地启动了很多任务,同一时刻只会有一个线程正在执行,其余的均处于等待状态
在Android 3.0之前是并没有SerialExecutor这个类的,那个时候是直接在AsyncTask中构建了一个sExecutor常量,并对线程池总大小,同一时刻能够运行的线程数做了规定,代码如下所示
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final int KEEP_ALIVE = 10;
……
private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
如果不想使用默认的线程池,还可以自由地进行配置。比如使用如下的代码来启动任务:
Executor exec = new ThreadPoolExecutor(15, 200, 10,
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
new DownloadTask().executeOnExecutor(exec);
在 FutureTask 的 run 中
public void run() {
....
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
//这个 call()在 AsyncTask 初始化的时候复写了这个 call 方法
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
...
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
//在 call 方法中 调用了doInBackground()
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(result);
}
};