前言:本文章假定读者熟悉AsyncTask的基本用法。

下面,我们从构造一个AsyncTask开始讲起。构造函数中,它将初始化mWorkermFuture,而mWorker调用doInBackground完成实际的工作。

Created with Raphaël 2.1.0 client client AsyncTask() AsyncTask() execute() execute() new AsyncTask() mWorker = new WorkerRunnable() mFuture = new FutureTask(mWorker) executor.execute(mFuture);
mWorker = new WorkerRunnable<Params, Result>() {    public Result call() throws Exception {        mTaskInvoked.set(true);        Process.setThreadPriority(                Process.THREAD_PRIORITY_BACKGROUND);        Result result = doInBackground(mParams);        Binder.flushPendingCommands();        return postResult(result);    }};

执行成功的情况下,postResult(result)最后会调用onPostExecute(),将结果发布至主线程。 同时,该return语句也将结果存放至 mFuture中。
此外需要注意的一点是,这里将线程优先级设置为了background,以防止占用过多的资源。

至于mFuture,主要用于执行任务的取消策略。具体的,可以看看AsyncTask.cancel()方法

public final boolean cancel(boolean mayInterruptIfRunning) {    mCancelled.set(true);    return mFuture.cancel(mayInterruptIfRunning);}

此外,AsyncTask.get()也通过mFuture,将结果返回给调用者。




Created with Raphaël 2.1.0 execute() execute() executeOnExecutor() executeOnExecutor() executeOnExecutor(sDefaultExecutor, params)

默认情况下,讲在sDefaultExecutor中执行对应的任务,可以直接调用executeOnExecutorsetDefaultExecutor(executor)方法,选择一种执行策略。

AsyncTask提供两种Executor的实现,分别是AsyncTask.THREAD_POOL_EXECUTORAsyncTask.SERIAL_EXECUTORsDefaultExecutor默认情况下为SERIAL_EXECUTOR。此外,由于这两个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);        }    }}

THREAD_POOL_EXECUTOR直接使用ThreadPoolExecutor实现,而SERIAL_EXECUTOR实际上也将工作交由THREAD_POOL_EXECUTOR处理,只是在内部使用一个ArrayDeque,以实现串行执行的功能。
此处需注意的,ArrayDeque.poll()方法并不阻塞,失败时,它将返回null,此时,也释放了mActive所指向(refer to)的对象,防止了内存的泄露。



Created with Raphaël 2.1.0 publishProgress() publishProgress() InternalHandler InternalHandler postResult() postResult() progress result

doInBackground()方法中,我们可以调用publishProgress()将进度发布至主线程。进度(grogress)和结果(result)的发布,都通过内部的InternalHandler类处理。

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

这里调用Looper.getMainLooper()以获取主线程的looper,从而确保结果发布至主线程。



此外,察看文档,还可以发现一个经常被忽略的函数:

// AsyncTaskpublic static void execute(Runnable runnable) {    sDefaultExecutor.execute(runnable);}

这里,我们可以将AsyncTask当成一个方便的线程池,偶尔用来执行一些Runnable(由于内部的线程池是公用的,不建议大量使用)。

还有一个我们直接查看源码可能无法发现的问题是,API level 11前,sDefaultExecutor 并非串行的。直接调用此方法,存在移植性问题。为此,我们可以使用support.v4包中的AsyncTaskCompat

public static <Params, Progress, Result>AsyncTask<Params, Progress, Result> executeParallel(        AsyncTask<Params, Progress, Result> task,        Params... params) {    if (task == null) {        throw new IllegalArgumentException("task can not be null");    }    if (Build.VERSION.SDK_INT >= 11) {        // From API 11 onwards, we need to manually select        // the THREAD_POOL_EXECUTOR        AsyncTaskCompatHoneycomb.executeParallel(task, params);    } else {        // Before API 11, all tasks were run in parallel        task.execute(params);    }    return task;}

AsyncTaskCompat只有一个静态方法executeParallel(),使用它,我们可以可移植地执行一个Runnable

基于此,如果应用需要明确的串行或并行执行,也应该显示调用executeOnExecutor()。由于该线程池是全局的,以此目的调用setDefaultExecutor并不是什么好主意。


另一点需要注意的是,THREAD_POOL_EXECUTOR的队列容量为128:

private static final BlockingQueue<Runnable> sPoolWorkQueue =        new LinkedBlockingQueue<Runnable>(128);




总结:AsyncTask总体上使用模板方法,将任务、取消、完成动作都交由子类实现,而执行策略则可以选择预定义的THREAD_POOL_EXECUTORSERIAL_EXECUTOR,也可以使用自己实现的Executor或自定义ThreadPoolExecutor。所以,执行策略还是非常灵活的。唯一的不足的没有(执行)失败策略,当然, 这也使得API更加的简单易用。

另外,在Executor中异步执行任务,而后通过Handler同步至主线程,也是Android平台的一个idiom,所谓的 half-sync, half-async。

文章中忽略了一些执行状态的细节,建议读者自己看看源代码,更细致地了解一下。

更多相关文章

  1. StageFright框架流程解读
  2. android onNewIntent
  3. TextView设置autoLink
  4. Android初级教程_获取Android控件的宽和高 .
  5. Android(安卓)碎碎记
  6. 初涉android中的回调机制
  7. Android(安卓)异步加载图片-AsyncTask
  8. Android之使用Android-query框架开发实战(二)
  9. android调用系统短信Intent时将预填接收号码和内容

随机推荐

  1. Android从远程服务器下载文件到本地sd卡
  2. 使用<data android: 建立和activity的关
  3. Android中GridView组件的使用
  4. Android 2.3 API改变大全
  5. Android比较好的10个开源框架
  6. [Android 問題] Make/Build Error: You a
  7. Android 开发者必备的十个工具(上)
  8. 3G定时开关 for android
  9. android投屏和媒体共享相关 && audio foc
  10. Android(安卓)TTS学习——TTS初体验(下)