AsyncTask是用来在实现在子线程执行任务后切换到UI线程,常见的比如下载任务的更新,执行下载后在UI线程实时更新进度条。由于是基本的API所以还是很有必要了解源码的。
使用
使用其实也很简单,主要是实现AsyncTask类,然后执行excute方法。其中有3个参数和4个方法是必须要掌握的。
private class MyAsyncTask extends AsyncTask<String, String, String> {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
}
@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
}
@Override
protected String doInBackground(String... strings) {
return null;
}
}
onPreExecute
这个方法是在UI线程执行,并且在后台任务开始前执行。
doInBackground
这个在线程执行,这里主要是做耗时任务。这个方法有参数和返回值,参数就是在调用execute传进来的参数,返回值就是我们经过一些列操作后返回给onProgressUpdate方法的,主要用于UI的更新。例如我下载到50%然后同志UI实时更新。
onProgressUpdate
从方法名看就是更新进度,这个参数就是doInBackground中返回的。
onPostExecute
这个方法就是任务执行完成后要执行的方法。参数也是执行的结果。
三个参数
掌握了这4个方法,这三个参数就很容易理解了。
第一个,是传入的参数。
第二个,是执行任务时进度更新的值。
第三个,任务执行结束的返回值。
源码
其实源码无非就是看内部的核心机制,和这几个方法的调用流程。最直观的就从execute方法开始。
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
这里直接调用了executeOnExecutor,传入了sDefaultExecutor和参数。
@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)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
先看下这个函数里面都做了什么,在分析sDefaultExecutor。executeOnExecutor这个函数是public的所以我们也可以直接通过这个函数执行任务。如果我们通过executeOnExecutor()这个方法的话就要自己创建一个Executor,因为默认的Executor是使用队列维护同时只有一个线程执行任务,多任务时会被添加到队列中,后面会讲到。
首先,进来先判断状态,如果如果不是没执行过的要抛出异常,这就是为什么如果执行两次任务会报java.lang.IllegalStateException这个错的原因。
其次,将状态改为正在执行。
然后,执行onPreExecute()方法,这就是为什么这个方法在主线程,而且在任务前执行。
再然后开始执行Executor的任务,这时候我们可以分析sDefaultExecutor了。
类里可以看到
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
这两个常量其实就是默认创建了一个Executor
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里面维护了一个队列,然后通过offer()在队列的末尾加入任务,通过poll()在头部检索出任务并删除,检索后赋值给mActive。因为首次mActive为null,所以加入了判断mActive==null的时候执行scheduleNext(),后面再有任务来的话mActive就不是null了,所以是在runable中,通过finally调用了scheduleNext(),这时候就会等任务执行完成后在执行下一个任务。这就是上面说的为什么默认的SerialExecutor只能同时在一个线程执行任务。
/**
* 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;
}
这个主要就是通过各种默认为的参数创建了一个线程池去执行任务。
这就是主要流程,但是在这个流程中还忽略了很多内容,在我们了解了整体框架流程后,在去填充我们想知道的细节,就更容易理解了。
首先看executeOnExecutor()方法中有两个很重要的内容一个是mWorker和mFuture。其实执行任务的时候传入了mFuture,而mFuture是一个mFutureTask真正执行的是mWorker。
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
this((Looper) null);
}
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*
* @hide
*/
public AsyncTask(@Nullable Handler handler) {
this(handler != null ? handler.getLooper() : null);
}
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*
* @hide
*/
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
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) {
@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);
}
}
};
}
在构造里创建了三部分内容,mHandler、mWorker、mFutur
可以看到首先会创建handler因为,线程通信还是需要依靠Handler。然后mWorker中主要就是执行doInBackground()然后将result传给postResult。
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发送一个what为MESSAGE_POST_RESULT,obj为result的message。
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;
}
}
}
这时候看handleMessage是怎么处理的。
这里主要是调用区分what是完成还是未完成完成的话就是调用finish方法,未完成就是onProgressUpdate方法,
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
在看finish方法就是判断是否取消然后调用onPostExecut方法将结果传入。
hadlerMessage还处理一个就是更新进度,那这个message是在哪里发的呢?
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
可以看到是通过publishProgress这个方法,所以我们如果需要更新进度的话要自己在doInBackground这个方法里调用publishProgress()方法传入进度。然后在才会在onProgressUpdate()这个方法中收到。
总结
至此 整个流程也就清晰了,这四个方法是分别在哪里调用的在能实现异步然后更新UI的功能,其实原理很简单,就是用了一个线城池然后我们在子线程实时通过Handler发送Message到UI线程中执行进度的任务,默认通过一个队列维护任务,也可以自定义Executor来实现多线程执行任务。