在之前的博客中已经介绍过了Handler,我们知道主线其实就是UI界面的守护进程一样,只有它才能修改UI界面上的元素,工作线程如果要更新界面需要通过主线程的Handler来更新,后来为了更加方便我们在子线程中更新UI元素,Android引入了一个AsyncTask类,通过它可以很方便地在后台线程和UI线程之间进行切换。极大得简便了我们的日常开发。

public abstract class AsyncTask<Params, Progress, Result> 

AsyncTask是一个抽象类,如果要使用需要继承这个类,这里需要再提下这三个参数的含义:

  • Params 表示在启动AsyncTask时传入的参数在后台任务中可以使用作为输入数据。如果不需要任何参数则可以传入Void
  • Progress 用于在后台任务在执行时调用onProgressUpdate方法在界面上显示当前的进度。
  • Result 表示当前后台任务完成后的返回结果

具体的用法见Android进阶之多线程技术这篇博客,这里就不再作展开介绍了,我们接下来就以一个场景来展开介绍

class DownloadAsyncTask extends AsyncTask<Void, Integer, Boolean> {  

@Override
protected void onPreExecute() {
downloadProgressDialog.show();
}
@Override
protected Boolean doInBackground(Void... params) {
try {
while (true) {
int process = downloadTask();
publishProgress(process);
if (process >= 100) {
break;
}
}
} catch (Exception e) {
Log.e(TAG,"There is something error !");
return false;
}
return true;
}
@Override
protected void onProgressUpdate(Integer... values) {
downloadProgressDialog.setMessage("下载进度:" + values[0] + "%");
}

@Override
protected void onPostExecute(Boolean result) {
downloadProgressDialog.dismiss();
if (result) {
Toast.makeText(context, "下载成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "下载失败", Toast.LENGTH_SHORT).show();
}
}
}

这是一个比较简单的模拟下载的示例,在downloadTask我们使用一个简单的sleep后更新返回值,我們先來看下AsycTask的构造方法:

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);
}
};

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);
}
}
};
}

这里创建了一个WorkerRunnable对象以及FutureTask对象,我们在继续深入代码之前先对这两个类有大概的了解下:
WorkerRunnable实现了Callable接口,是一个有返回值的线程任务。它的返回结果就是Result,FutureTask可以获取到执行结果并且可以取消执行任务,通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过FutureTask的get方法异步获取执行结果,FutureTask非常适合用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。另外,FutureTask还可以确保即使调用了多次run方法,它都只会执行一次Runnable或者Callable任务,或者通过cancel取消FutureTask的执行等。从上面描述是否看到了AyncTask的雏形。如果对这两个类想要有更多的了解可以通过如下两篇博客来了解,也相当于该自己留个坑后续再深入了解。

http://blog.csdn.net/linchunquan/article/details/22382487
http://blog.csdn.net/jackchen95/article/details/13631761

好了我们继续:
上面讲到我们创建了一个WorkerRunnable对象后放到FutureTask中运行。那么整个初始化就结束了,接着就调用execute方法启动任务。

@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}

紧接着调用我们的executeOnExecutor方法。

 @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;
}

这里传入的exec参数为sDefaultExecutor,它的定义如下

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

也就是说它是一个SerialExecutor,看下代码中有如下注释:
说明这是一个串行的任务,每次只能执行一个,当当前的任务结束的时候才允许执行下一个。这也是很多时候提到的AyncTask的弊端。我门这里先不讲这些。继续我们的源码分析。

/**
* An {@link Executor} that executes tasks one at a time in serial
* order. This serialization is global to a particular process.
*/

executeOnExecutor中会先判断当前的状态这里需要注意的是AysnTask是一个单次执行的任务,一旦执行结束后再调用excute就会抛出错误,必须重新new一个。在状态为PENDING的情况下说明当前的AsyncTask尚未执行,这时候会将当前状态置为Status.RUNNING
并在调用onPreExecute后调用SerialExecutor的execute方法。

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方法中我们调用了FutureTask 的 run()方法(FutureTask 代码不在framework层中而是在libcore下)

public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
Callable<V> 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);
}
}

在这里调用了

result = c.call()

也就是介绍构造函数时提到的WorkRunable,为了避免大家在这关键关头翻代码我直接再次贴在下面了。

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);
}

};

这里大家是不是看到了doInBackground方法?那么执行完结果怎么返回到主线程呢?我们注意到最后通过postResult来将结果返回。

private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}

我们继续看下这个方法:这里我们看到了Handler的影子。它会通过getHandler获取到一个Handler,这个Handler实际上就是MainHandler,我们拭目以待:

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
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}

看到了吧在创建InternalHandler的时候会将getMainLooper传入。通过这个Handler将MESSAGE_POST_RESULT消息发送给MainLooper,在消息循环中执行到这个消息的时候就调用InternalHandler的handleMessage,进而调用:

result.mTask.finish(result.mData[0]);

在紧接着就是调用finish方法,并将result作为参数传入:

private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}

在这里就调用了onPostExecute方法。

最后再看下publishProgress这个方法:

@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}

其实如果上面的流程大家看得懂的话这里只要贴出代码就知道整个过程了:就是往MainLooper上发送MESSAGE_POST_PROGRESS消息InternalHandler收到消息后调用onProgressUpdate执行。

其实这里还涉及到SerialExecutor的串行执行的问题,这个将放在后面的博客中介绍。

Contents