AsyncTask使用
AsyncTask是一个抽象类,使用时需要创建子类继承。其类声明如下:
public abstract class AsyncTask
继承时需要指定三个泛型参数:
Params:开始执行任务时需要传入的参数类型
Progress:用于显示当前任务执行进度
Result:任务执行结束后的返回结果。
下面是AsyncTask的一个基本使用:
class DownloadTask extends AsyncTask {
//任务开始执行之前调用,一般用于界面初始化。
@Override
protected void onPreExecute() {
}
//在子线程中执行耗时操作
@Override
protected Boolean doInBackground(Void... params) {
try {
while (true) {
int downloadPercent = doDownload();
publishProgress(downloadPercent);
if (downloadPercent >= 100) {
break;
}
}
} catch (Exception e) {
return false;
}
return true;
}
//在后台任务中调用publishProgress之后,这个函数就会被调用,一般用来更新界面。
@Override
protected void onProgressUpdate(Integer... values) {
progressDialog.setMessage("当前下载进度:" + values[0] + "%");
}
//任务结束时调用
@Override
protected void onPostExecute(Boolean result) {
progressDialog.dismiss();
if (result) {
Toast.makeText(context, "下载成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "下载失败", Toast.LENGTH_SHORT).show();
}
}
}
AsyncTask的使用十分简洁明了,但是底层是怎么实现的?这就需要结合源码来分析了。
AsyncTask源码解析
AsyncTask通常调用new DownloadTask().execute()开始执行任务。那么我们就从这里开始研究。首先是构造函数。构造函数首先初始化了一个Handler对象。接着初始化了一个mWorker,然后将mWorker作为参数初始化了mFuture。虽然初始化了两个参数,但是并没有开始执行操作,至于这两个对象的作用是什么需要进一步分析。
public AsyncTask() {
this((Looper) null);
}
public AsyncTask(@Nullable Handler handler) {
this(handler != null ? handler.getLooper() : null);
}
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
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);
}
return result;
}
};
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);
}
}
};
}
接着看execute函数,调用了executeOnExecutor函数,传进sDefaultExecutor作为参数。
public final AsyncTask execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
在executeOnExecutor会先对状态进行判断,因此如果多次调用execute就会抛出异常。接着就是调用onPreExecute(),在这里可以进行界面的初始化工作。接着调用传入的sDefaultExecutor.execute,而sDefaultExecutor是SerialExecutor,因此需要到SerialExecutor看具体做了什么。
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的静态对象。在SerialExecutor中持有一个ArrayDeque,这是一个双端队列,可以从首尾操作元素。在execute中将一个Runnable对象添加到队尾。第一次加载前mActive=null,因此会调用scheduleNext(),scheduleNext()会从ArrayDeque队首取出任务,并使用THREAD_POOL_EXECUTOR.execute进行执行,THREAD_POOL_EXECUTOR其实就是一个线程池。最终执行的是之前添加到队列中的那个Runnable,在这个Runnable的run中会调用mFuture.run.
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);
}
}
}
而mFuture是个FutureTask,再来看FutureTask.run.这里吗调用了Callable.call();而这个Callable就是在构造函数中传进去的mWorker.
public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
Callable c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
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的call做了什么。在这里终于看到了doInBackground,接着调用postResult
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);
}
return result;
}
};
postResult中通过Handler发送MESSAGE_POST_RESULT消息。
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult(this, result));
message.sendToTarget();
return result;
}
这样在handleMessage中就会进入MESSAGE_POST_RESULT的case,调用finish
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;
}
}
}
在finish中如果没有被取消,则调用onPostExecute。
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
而当调用publishProgress,同样会发送MESSAGE_POST_PROGRESS的消息,最终会调用
onProgressUpdate。
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult