上篇介绍了Handler实现主线程和子线程间的通信,在Android中还提供了一种更方便使用的AsyncTask来实现主线程和子线程通信.使用AsyncTask就不用自己去开启子线程创建Handler、重写handlerMessage()等操作了,我们只需要一个AsyncTask类即可搞定。但是在使用场合上,它适用于操作时间短的场合(最多几秒钟),如果是长时间的操作不建议使用AsyncTask,而是推荐使用Java的Executor、ThreadPoolExecutor和FutureTask等类来协助Handler来完成,这三个类都是jdk的java.util.concurrent包下的类。先看下AsyncTask的使用方法:
private class UITask extends AsyncTask<String, Void, String> {
private String name;
public UITask(String name) {
super();
this.name = name;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
String str = mContentView.getText().toString();
mContentView.setText(str + "\n" + name);
}
@Override
protected String doInBackground(String... params) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return params[0];
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
String str = mContentView.getText().toString();
mContentView.setText(str + "\n" + result);
}
}
在使用的时候直接new一个UITask对象然后调用execute(...)即可。虽然AsyncTask用起来很简单,但是需要遵循以下几个原则:
(1)AsyncTask必须在UI线程中加载
(2)AsyncTask实例必须在UI线程中创建
(3)execute(...)方法必须在UI线程中调用
(4)绝对不要去调用onPreExecute()、DoInBackground()、onPostExecute()方法
(5)每个AsyncTask实例只能被执行一次,如果多次执行就会抛出异常
那么AsyncTask是如何工作的呢?在使用AsyncTask请求任务时,通常调用execute(...)方法,此方法最终会调用executeOnExecutor()方法,源码如下:
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(),可以看出来,此方法在主线程直接调用到了,并不在子线程中
onPreExecute();
//赋值参数,mWorker是一个实现了java.util.concurrent.Callable<Result>接口的WorkerRunnable实例,
//在WorkerRunnable类中只有一个Params[] mParams;成员变量,其他什么都没有。
mWorker.mParams = params;
//Executor开始执行,注意,exec默认的是一个sDefaultExecutor对象,该对象是实现Exector接口的SerialExecutor实例
exec.execute(mFuture);
//返回当前AsyncTask的实例
return this;
}
这里我们要注意,当我们调用execute()方法时,AsyncTask在执行任务时会被加一个规范,这个规范就是:所有的任务都是同步的,只有当一个任务执行完毕后下一个任务才可以执行。因为此时这个exec是一个SerialExecutor实例,它是一个顺序的执行者,看下他实现的SerialExecutor源码:
private static class SerialExecutor implements Executor {
//ArrayDeque双向队列
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
//最终执行的就是此方法,
public synchronized void execute(final Runnable r) {
//添加一个Runnable对象到队列中
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
//然后调用scheduleNext(),
if (mActive == null) {
scheduleNext();
}
}
//THREAD_POOL_EXECUTOR是一个ThreadPoolExecutor线程池,会执行FutureTask任务,者流先取出一个Runnable对象,然后去执行,就这样它就保证了任务的顺序执行
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
此外,在executeOnExecutor()方法中我们还看到了一个mFuture对象,此对象就是一个FutureTask实例,我们看下它在AsyncTask的构造方法中被创建:
public AsyncTask() {
//创建WorkerRunnable对象,
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
//返回DoInBackground()方法执行的结果
return postResult(doInBackground(mParams));
}
};
//创建FutureTask实例,
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的call()方法中,当doInBackground()方法执行完毕后会将Result参数传递给postResult()方法,并执行它,那么看下postResult()方法做了什么事情:
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
//用Handler取得一个Message对象,并将Result赋值给obj
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
//发送一个消息出去给handlerMessage()处理,
message.sendToTarget();
return result;
}
在postResult()方法中sHandler对象是AsyncTask的一个Handler内部类,源码如下:
private static class InternalHandler extends Handler {
@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()中,如果是已经执行完毕就调用finish(),方法,如果是正在执行就调用onProgressUpdate()方法,那么当我们的doInBackground()方法执行完毕后在onPostExecute(0方法中更新UI的方法是啥时候调用的呢?莫激动,在handleMessage()中只有两个判断调用finish()和onProgressUpdate(),既然onProgressUpdate()中没有调用onPostExecute(),那肯定在finish()中调用了,我们去看看finish()方法:
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
没错,onPostExecute()方法就是在finish()中调用的,如果说在没有执行完就取消了,就不会执行onPostExecute()了。完了之后就将mStatus的状态设置为FINISHED。
当然了,上面我们也说道了,当我们用execute()来执行任务时,多个任务是顺序执行的,后一个任务必须等前一个任务执行完后在执行,那有时候我们有很多任务需要同时执行,不要等待那么久该怎么办呢?不要急,上面的分析已经给出了答案,那就是我们直接调用executeOnExecutor(Executor exec, Params... params)方法,该方法的第二个参数和execute()的一致,第一个参数是指定一个执行者,在AsyncTask中已经提供了一个THREAD_POOL_EXECUTOR线程池,看下他的创建:
/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
这个线程池可以一次同时执行9个任务(线程),如果还有更多的任务那就需要等待了,这些等待的任务就会放在sPoolWorkQueue阻塞队列。当然了,如果AsyncTask提供的线程池仍然不能满足你的需求,你也可以自己配置一个线程池,指定大小、阻塞队列、拒绝策略等。然后调用
现在我们来捋一捋AsyncTask的执行流程:首先我们需要继承AsyncTask来实现自己的AsyncTask,并至少重写一个doInBackground()方法。流程如下:
(1)创建一个AsyncTask实例,此时完成了Callable和Future的创建,并且在Callable的call()方法中完成了对doInbackgound()的调用,同时根据doInbackground()方法的返回来调用postResult()方法然后使用Handler发送消息最终将子线程执行的结果发送给主线程的onPostResult()方法中。
(2)用户开始调用execute()或executeOnExecutor()方法,,此时线程池开始线程的执行。然后调用到了executeOnExcutor()方法,该方法就调用到SeriakExecutor的execute(mFuture)方法,注意传递了一个mFuture对象,而mFuture
由mWork构造,所有会调用到了WorkRunnable的call()方法中的doInBackground()方法,然后根据此方法返回的结果调用postResult()方法,然后获取Message,并发送消息给InternalHandler的handleMessage()方法来处理,也就是调用postResult(),从而调用到了onPostExecute()方法。