AsyncTask是一个抽象类,它是由Android封装的一个轻量级异步类,它可以在线程池中执行后台任务,然后把执行的进度和最终的结果传递给主线程并在主线程中更新UI。
首先我们看看它的定义:
public abstract class AsyncTask
3种泛型类型分别表示参数类型,后台任务执行的进度类型,返回的结果类型,如果某个参数不需要,可以设置为void。
一个异步任务的执行一般包括以下几个步骤:
- execute(Params… params):执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行。
- onPreExecute():在execute
方法被调用后立即执行,执行在UI线程,一般用来在执行后台任务之前对UI做一些标记。
- doInBackground(Params… params):在onPreExecute()
方法完成后立即执行,用于执行较为耗时的操作,此方法将接收输入参数和返回结果计算。在执行过程中可以调用publishProgress(Progress... values
)来更新进度信息。
- onProgressUpdate(Progress… values):执行在UI现在。在调用publishProgress(Progress... values
)时,此方法被执行。直接将进度信息更新到UI组件上。
- onPostExecute(Result result):执行在UI线程。当后台操作结束时,此方法将会被调用,doInBackground
方法返回的计算结果将作为参数传递到此方法中,直接将结果显示到UI组件上。
先通过一个下载图片的小例子来体验它:
public class AsyncDemo extends AsyncTask{
private String mUrl;
private onDownLoadInterface mCallback;
public interface onDownLoadInterface{
void onStarting();
void onFinish(Bitmap bitmap);
}
public AsyncDemo(onDownLoadInterface callback){
mCallback = callback;
}
@Override
protected void onPreExecute() {
mCallback.onStarting();
}
@Override
protected Bitmap doInBackground(String... strings) {
mUrl =strings[0];
Bitmap bitmap = null;
URLConnection connection;
InputStream in;
try {
connection = new URL(mUrl).openConnection();
in = connection.getInputStream();
//为了看到效果
Thread.sleep(2000);
BufferedInputStream bis =
new BufferedInputStream(in);
bitmap = BitmapFactory.decodeStream(bis);
in.close();
bis.close();
}catch (MalformedURLException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}catch (InterruptedException e){
e.printStackTrace();
}
return bitmap;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
@Override
protected void onPostExecute(Bitmap bitmap) {
mCallback.onFinish(bitmap);
}
}
AsyncDemo asyncDemo = new AsyncDemo(this);
asyncDemo.execute(URL);
@Override
public void onStarting() {
dialog = new AlertDialog.Builder(this)
.setMessage("图片正在下载")
.setTitle("下载")
.create();
dialog.show();
}
@Override
public void onFinish(Bitmap bitmap) {
dialog.dismiss();
mImageView.setImageBitmap(bitmap);
}
然后我们就可以下载一张图片,效果如图:
那么它下载这一张图片,经历了什么呢?
首先我们先看看AsyncTask里面的几个核心的方法:
//执行在工作线程
@WorkerThread
protected abstract Result doInBackground(Params... params);
//执行在DoInBackground之前,并且执行在UI线程
@MainThread
protected void onPreExecute() {
}
// 后台操作执行完会调用的方法,在此更新UI
@MainThread
protected void onPostExecute(Result result) {
}
//在此更新进度
@MainThread
protected void onProgressUpdate(Progress... values) {
}
@MainThread
public final AsyncTask execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
//执行任务,注意excute方法必须在UI线程中调用
//exec :执行任务的线程池
@MainThread
public final AsyncTask executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
//检测状态,只有在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();
//UI线程,传递过来的参数
mWorker.mParams = params;
//交给线程池管理器进行调度,参数为FutureTask类型
exec.execute(mFuture);
return this;
}
//发布进度
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult
在上面代码中,我们看到有一个Stauts的枚举类,Status枚举类代表了AsyncTask的状态:
public enum Status {
/**
* 未执行状态
*/
PENDING,
/**
*执行中
*/
RUNNING,
/**
* 执行完成
*/
FINISHED,
}
在调用execute方法时,如果是非PENDING状态则会抛出异常,这也就解释了为什么一个AsyncTask实例只能那个运行一次。
在execute方法中,涉及到了三个变量:sDefaultExecutor,mWork,mFuture:
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
private final WorkerRunnable mWorker;
private final FutureTask mFuture;
private static class SerialExecutor implements Executor
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));//核心线程数
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;//最大线程数
private static final int KEEP_ALIVE_SECONDS = 30;//线程空闲时留存的时间
//线程工厂
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
//创建一个线程
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
//任务队列
private static final BlockingQueue sPoolWorkQueue =
new LinkedBlockingQueue(128);
//线程池
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;
}
//默认的任务调度是顺序执行
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
//顺序执行的Executor
private static class SerialExecutor implements Executor {
final ArrayDeque mTasks = new ArrayDeque();
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);
}
}
}
从上述代码中我们可以看到,sDefaultExecutor只负责将异步任务分发给THREAD_POOL_EXECUTOR线程池
,因此真正执行任务的地方是THREAD_POOL_EXECUTOR。
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*
* @hide
*/
public AsyncTask(@Nullable Looper callbackLooper) {
//得到在UI线程中的Handler
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
//WorkRunnable是AsyncTask的一个抽象内部类
mWorker = new WorkerRunnable() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//执行DoInBackground
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
//最后将结果投递到UI线程
postResult(result);
}
return result;
}
};
//mFuture会调用mWork做后台任务,完成后会调用done方法
mFuture = new FutureTask(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);
}
}
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult(this, result));
message.sendToTarget();
return result;
}
private static abstract class WorkerRunnable implements Callable {
Params[] mParams;
}
我们可以看到在mWork中会通过postResult
将结果投递出去,但是如果期间发生了异常,postResult
将不会调用,那么最终在Future的done
方法中通过postResultIfNotInvoked
检查是否执行成功,如果执行成功且未调用postResult
,那么就调用postResult
,否则忽略该执行结果.
在创建AsyncTask对象后,我们会执行AsyncTask的execute
方法:
@MainThread
public final AsyncTask execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
、
@MainThread
public final AsyncTask 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;
}
//sDefaultExecutor是SerialExecutor实例
private static class SerialExecutor implements Executor {
//双端队列
final ArrayDeque mTasks = new ArrayDeque();
Runnable mActive;
//mFuture实现了Runnable
public synchronized void execute(final Runnable r) {
//将Runnable对象放入队列
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);
}
}
}
在execute
方法接收一个Runnable
对象,我们传入的mFuture
正好实现了该接口,方法内部首先通过双端队列ArrayDeque的offer
方法把一个新创建的Runnable对象入队。然后判断mActive
是否为空?第一次执行肯定是为空的,所以会调用scheduleNex
t方法,scheduleNext
方法首先从双端队列中得到一个元素,如果不为空,就调用THREAD_POOL_EXECUTOR.execute
方法,THREAD_POOL_EXECUTOR
是一个线程池,也就是说我们把从双端队列中得到的任务交给线程池去执行(接下来的代码都在工作线程中执行)
还记得,上面我们看到THREAD_POOL_EXECUTOR
是ThreadPoolExecutor的实例(ThreadPoolExecutor实现了Excutor):
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
之前的博客中有分析过这段代码,这段代码的主要功能其实就是将异步任务加入将要执行的队列。
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
//得到运行状态和活动线程数
int c = ctl.get();
//得到线程池的状态
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
//得到活动线程数
int wc = workerCountOf(c);
//boolean类型的core,true表示在新增线程时会判断当前活动线程数是否少于corePoolSize,
// false表示新增线程前需要判断当前活动线程数是否少于maximumPoolSize
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
if (compareAndIncrementWorkerCount(c))//检查是否可以新增线程
break retry;
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
w = new Worker(firstTask);//生成一个Work对象,同时 生成一个新线程
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int rs = runStateOf(ctl.get());
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
workers.add(w);//将w添加到works里,这是一个HashSet集合对象
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {//如果添加成功,就异步执行该任务。在这里就是启动了mFuture任务
t.start();//线程启动,那么则会调用到run方法。在这里就是调用了mFuture的run方法
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
我们可以分析到,线程池在execute一个任务的时候,先是判断是否可以加入任务队列,如果可以,就新建一个线程对任务进行执行,其实也就是调用任务的run方法
public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
//在构造mFuture的时候,传入了一个mWork,也就是callable,
//mWork是Callable的实例,Callble的call方法是可以返回结果的
Callable c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
//在这里就是调用mWork的calll方法,得到结果.
//在mWork的call方法中,会调用doInBackground方法
result = c.call();
ran = true;
} catch (Throwable ex) {
//如果发送异常
result = null;
ran = false;
//调用setException方法,会调用done方法
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);
}
}
mWorker = new WorkerRunnable() {
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);//投递结果给UI线程
}
return result;
}
};
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult(this, result));
message.sendToTarget();
return result;
}
public void sendToTarget() {
target.sendMessage(this);//target就是Handler
}
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(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]);//发送结果
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
分享一张图: