常用例子
本文依照以下常用例子展开:
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) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
new DownloadFilesTask().execute(url1, url2, url3);
AsyncTask的使用方法太常见了,这里不做详述。值得注意的是AsyncTask有以下用法:
DownloadFilesTask mDownloadFilesTask = new DownloadFilesTask().execute(url1, url2, url3);
Long result = mDownloadFilesTask.get(); // 如果doInBackground还没执行完毕,那么堵塞直到它返回结果为止。
可以通过get()方法来获得AsyncTask的运行结果,这是通过java.util.concurrent的FutureTask类来完成的。AsyncTask类依赖于java.util.concurrent,task的执行和调度都由FutureTask、Executor、LinkedBlockingQueue等类来完成,下文会对其展开介绍。
源码解析
AsyncTask的状态
AsyncTask有三种状态:
public enum Status {
PENDING,
RUNNING,
FINISHED,
}
对象初始化完毕后为PENDING状态,execute()被执行时转变成RUNNING状态,onPostExecute执行后变成FINISHED状态。execute()方法仅可以在task为PENDING状态下调用,否则会抛出IllegalStateException
AsyncTask的初始化
AsyncTask有很多静态属性:
public abstract class AsyncTask<Params, Progress, Result> {
...
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<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
...
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
private static InternalHandler sHandler;
...
private static class SerialExecutor implements Executor {
...
}
其中:
sThreadFactory:供THREAD_POOL_EXECUTOR使用。为每个thread设定自增的name。
sPoolWorkQueue:供THREAD_POOL_EXECUTOR使用。
THREAD_POOL_EXECUTOR:供SerialExecutor使用,task真正执行的场所。
SERIAL_EXECUTOR:默认executor的实现,下文会对其详述。
sHandler:初始化时注入主线程的looper,接收MESSAGE_POST_RESULT和MESSAGE_POST_PROGRESS消息。
其中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);
}
}
}
代码逻辑如下所示:
- 当SerialExecutor对象的execute(runnable)执行时,首先会将runnable对象包装一下,然后放到一个FIFO的队列mTasks当中。如果是首次执行,那么scheduleNext()方法会被调用。
- 在scheduleNext()方法中,mTasks中的runnable被取出并赋给mActive变量,然后将mActive放到THREAD_POOL_EXECUTOR中执行。
- 在THREAD_POOL_EXECUTOR中调用run()方法,然后再次调用scheduleNext()方法取出下一个runnable。
接下来看一下AsyncTask的初始化方法:
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
return postResult(doInBackground(mParams));
}
};
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 occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
WorkerRunnable的源码如下所示:
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
可以看到WorkerRunnable继承于Callable,因此可以放到Executor中执行。因此mWorker这个匿名类的call方法会在Executor中调用。
首先将mTaskInvoked设置为true。mTaskInvoked用于检查当前的mWorker是否已经被执行(有可能还没执行就cancel了)。然后设置一下线程优先级,最后调用postResult()方法向sHandler发送MESSAGE_POST_RESULT消息。
接下来看mFuture。mFuture是一个FutureTask对象,可以通过调用mFuture.get()来堵塞式地等待task的执行结果,详情可以参考这里。done()方法会在mWorker结束(无论是cancel还是正常finish)时调用。其中postResultIfNotInvoked()源码如下所示:
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<Result>(this, result));
message.sendToTarget();
return result;
}
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;
}
}
}
如果当前mWorker没有被执行过,则执行postResult()方法。这里保证了无论mWorker是否正常结束,主线程的回调依然会正常执行。
AsyncTask的执行
通过类似调用new DownloadFilesTask().execute(url1, url2, url3);
可以执行一个AsyncTask。execute方法的源码如下所示:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
//1. 检查和设置task的状态
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;
//2. 回调api
onPreExecute();
//3. 设置params和在sDefaultExecutor上执行mFuture
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
代码逻辑见注释。结合前文对mFuture和mWorker的讲解,可以画出AsyncTask的执行流程图:
+----------+ +--------+ +---------+ +---------------+ +--------------------+ +------------+ +--------------+
|MainThread| |sHandler| |AsyncTask| |SERIAL_EXECUTOR| |THREAD_POOL_EXECUTOR| | FutureTask | |WorkerRunnable|
+----+-----+ +---+----+ +----+----+ +-------+-------+ +----------+---------+ +------+-----+ +-------+------+
| | new | | | | |
+---------------------------------------> | | | | |
| | | | | | |
| | +----------+ | | | |
| | set mWorker and mFuture | | | | |
| | | | | | | |
| | | <--------+ | | | |
| | | | | | |
| | | | | | |
| execute(Params... params) | | | | |
+---------------------------------------> | | | | |
| | | | | | |
| | onPreExecute() | | | | |
| <---------------------------------------+ exec.execute(mFuture)| | | |
| | +---------------------> | scheduleNext() | | |
| | | +------+ | | |
| | | | | | | |
| | | | | | | |
| | | | <----+ | | |
| | | | execute(mActive) | | |
| | | +-----------------------> | run() | |
| | | | +------------------> | call() |
| | | | | +-----------------> |
| | | doInBackground() | | | |
| | | <----------------------------------------------------------------------------------------+
| | MESSAGE_POST_RESULT| | | | |
| | <-------------------------------------------------------------------------------------------------------------+
| | finish() | | | | done() |
| +------------------> | | | | <-----------------+
| onPostExecute(result) | | | | |
| <---------------------------------------+ | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
+ + + + + + +
查看原文:http://legendmohe.net/2015/11/18/android-asynctask%e6%ba%90%e7%a0%81%e8%a7%a3%e6%9e%90/