上篇介绍了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; }
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。
/** * 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()方法。