AsyncTask是Android提供的一个轻量级异步任务机制,使用AsyncTask可以方便的执行异步任务,并将结果更新到main thread。AsyncTask中是通过Handler机制来让work thread和main thread通信的。如果你对Handler还不了解的话,可以通过我的这篇博客来了解Android的Handler机制。Android 异步消息处理机制
  在这篇文章中我们将了解AsyncTask的基本用法以及从源码的角度来分析AsyncTask机制,首先我们来了解下开发过程中AsyncTask的使用

AsyncTask的基本用法

AsyncTask类的基本方法:

public abstract class AsyncTask<Params, Progress, Result> {/**     * Override this method to perform a computation on a background thread. The     * specified parameters are the parameters passed to {@link #execute}     * by the caller of this task.     *     * This method can call {@link #publishProgress} to publish updates     * on the UI thread.     *     * @param params The parameters of the task.     *     * @return A result, defined by the subclass of this task.     *     * @see #onPreExecute()     * @see #onPostExecute     * @see #publishProgress     */    @WorkerThread    protected abstract Result doInBackground(Params... params);    /**     * Runs on the UI thread before {@link #doInBackground}.     *     * @see #onPostExecute     * @see #doInBackground     */    @MainThread    protected void onPreExecute() {    }    /**     * 

Runs on the UI thread after {@link #doInBackground}. The * specified result is the value returned by {@link #doInBackground}.

* *

This method won't be invoked if the task was cancelled.

* * @param result The result of the operation computed by {@link #doInBackground}. * * @see #onPreExecute * @see #doInBackground * @see #onCancelled(Object) */
@SuppressWarnings({"UnusedDeclaration"}) @MainThread protected void onPostExecute(Result result) { } /** * Runs on the UI thread after {@link #publishProgress} is invoked. * The specified values are the values passed to {@link #publishProgress}. * * @param values The values indicating progress. * * @see #publishProgress * @see #doInBackground */ @SuppressWarnings({"UnusedDeclaration"}) @MainThread protected void onProgressUpdate(Progress... values) { }}

  从上面AsyncTask的代码可以看到,AsyncTask是一个抽象类,我们如果想要使用的话必须先创建它的子类,并实现它的抽象方法doInBackground,根据功能需要我们还可以重写onPreExecute、onPostExecute、onProgressUpdate。从注释我们就可以知道onPreExecute、onPostExecute、onProgressUpdate这几个方法是运行在main thread,doInBackground是运行在workthread中的。我们把耗时的操作放在doInBackground进行,当doInBackground执行完之后会把结果返回给onPostExecute,我们可以在onPostExecute做一些更新UI的操作。onPreExecute在doInBackground之前执行,用于执行准备工作,onProgressUpdate用来更新后台任务的执行进度。
  AsyncTask有三个泛型参数,分别是Params, Progress, Result。Params是指后台任务运行的参数,用于在doInBackground使用,Progress是用来指示后台任务执行进度的单位,Result是后台任务的返回结果,在doInBackground方法中返回,交给onPostExecute处理。这些参数不需要时可以用Void代替。
  在本文中我们自定义一个简单的AsyncTask类,代码定义如下:

public class TestAsyncTask extends AsyncTask<Void, Integer, Void> {    private String taskName;    public TestAsyncTask(String name) {        super();        taskName = name;    }    @Override    protected void onPreExecute() {        super.onPreExecute();    }    @Override    protected void onProgressUpdate(Integer... values) {        super.onProgressUpdate(values);    }    @Override    protected void onPostExecute(Void aVoid) {        super.onPostExecute(aVoid);        Log.v("stone", "task = " + taskName + " onPostExecute in " + Thread.currentThread().toString());    }    @Override    protected Void doInBackground(Void... params) {        Log.v("stone", "task = " + taskName + " doInBackground in " + Thread.currentThread().toString());        try {            Thread.sleep(10000);        } catch (InterruptedException e) {            e.toString();        }        return null;    }}//AsyncTask的两种启动方式new TestAsyncTask("task_" + i).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);new TestAsyncTask("tasktesk_" + i).execute();

  到目前为止我我们已经大致了解了AsyncTask的使用,以及启动后台任务的两种方式,execute和executeOnExecutor。在executeOnExecutor中我们使用了AsyncTask自定义的THREAD_POOL_EXECUTOR,它是一个ThreadPoolExecutor。这两种后台任务的启动方式有什么区别呢?一个应用中最多可以new多个AsyncTask呢?多个任务是并行处理还是串行处理呢?最多同时有多少个任务在处理呢?下面我们将从源码的角度来回答上面的问题,由于AsyncTask从出现到现在已经有了多次改动,下面我的分析将是基于API 23的源码来进行的,请各位注意不同API版本的AsyncTask实现是有差异的。

AsyncTask机制详解

  通过上文我们已经知道了AsyncTask的简单用法,下面我将从源码的角度来分析,一个AsyncTask从创建到执行的过程。首先一个任何AsyncTask子类的创建都会调用AsyncTask的默认构造函数AsyncTask(),下面我们来看一下这个方法的定义:

     public AsyncTask() {        mWorker = new WorkerRunnable() {            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(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);                }            }        };    }

  代码很简单,初始化了mWorker 和mFuture 这两个对象,我们暂时先不管立面的具体实现,只要知道这个mFuture 会交给Executor去执行。现在AsyncTask对象已经创建好了,我们来看AsyncTask的执行过程。我们先来分析execute()方法,该方法的定义如下:

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

  execute的代码实际上直接调用了executeOnExecutor方法,并且传入了一个叫做sDefaultExecutor的Executor对象。接着我们来看下executeOnExecutor方法的定义:

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

  在executeOnExecutor中,我们先调用了onPreExecute()方法,这就解释了为什么onPreExecute方法是最新被调用的。我们把运行参数params赋给mWorker对象,mWorker实现了callable接口。把mFuture交给我们传入的Executor来执行。对面我们前文提到了AsyncTask的两种启动方式,他们执行方式的不同是因为传入的Executor不同导致的。我们前面提到过execute方法传给executeOnExecutor的是一个sDefaultExecutor对象,通过源码来看一下sDefaultExecutor是什么:

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

  我们看到sDefaultExecutor 被赋值为SERIAL_EXECUTOR,我们来看一下SERIAL_EXECUTOR是如何定义的:
  

    /**     * An {@link Executor} that executes tasks one at a time in serial     * order.  This serialization is global to a particular process.     */    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

  SERIAL_EXECUTOR 是一个SerialExecutor对象,我们来看一下SerialExecutor的实现:
  

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

  到这里我们可以知道,通过execute启动AsyncTask任务,会把任务一个一个添加到mTasks中,在执行完一个任务后才会去执行下一个任务,mTasks的大小没有限制,所以理论上通过execute启动AsyncTask任务这种方式可以创建无数个task,并且所有的task是串行执行的。这个runnable参数就是我们在AsyncTask构造函数中初始化的mFuture。我们接着再来看一下构造函数的源码:
  

     public AsyncTask() {        mWorker = new WorkerRunnable() {            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(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);                }            }        };    }

  我们看到在初始化mWorker 对象时,在它的call方法里面调用了doInBackground方法,执行完doInBackground之后会调用postResult(result)来传递doInBackground的返回结果。我们来分析下postResult方法看看结果是如何传递的。
  

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

  postResult方法中主要是生成了一个MESSAGE_POST_RESULT消息,并将消息发送给了target handler。现在我们就要来看看这个Handler对象是什么,就知道是把消息发送到了哪个线程中。我们来看一下getHandler()方法的实现:
  

    private static Handler getHandler() {        synchronized (AsyncTask.class) {            if (sHandler == null) {                sHandler = new InternalHandler();            }            return sHandler;        }    }

  看到这里,我们知道这个handler是一个InternalHandler对象,我们接着来看一下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;            }        }    }

  看到这里已经很清楚,这个handler是绑定了主线程loop的handler,所以接下来的工作就从工作线程切换到主线程中去执行。在handleMessage中可以看到MESSAGE_POST_RESULT会导致调用result.mTask.finish(result.mData[0])。这个就是AsyncTask的finish方法,我们来看一下finish方法的实现:
  

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

  finish方法里面会做判断,如果 isCancelled()返回的是true,就会去执行onCancelled,否则就会调用onPostExecute方法。至此我们就走完了execute方式的启动流程。通过以上的分析,我们可以知道这种方式下AsyncTask的对象可以创建任意多个并执行,且是顺序执行的。
  对于executeOnExecutor启动方式,他的执行方式和传入的Executor相关,每个任务的执行逻辑和execute启动方式是一样的。executeOnExecutor方式中我们传入的参数是AsyncTask.THREAD_POOL_EXECUTOR,这是AsyncTask默认帮我们配置的Executor。我们来具体看下这个Executor的配置情况:
  

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;    private static final int KEEP_ALIVE = 1;    private static final ThreadFactory sThreadFactory = new ThreadFactory() {        private final AtomicInteger mCount = new AtomicInteger(1);        public Thread newThread(Runnable r) {            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());        }    };    private static final BlockingQueue sPoolWorkQueue =            new LinkedBlockingQueue(128);    /**     * 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);

  这个ThreadPoolExecutor配置如下:核心线程数为CPU核个数+1,最大线程数是2倍的CPU核个数+1,任务排队队列大小为128,所以假设我们的手机CPU核的个数为8,在核心线程数为9,最大线程数为17。所以根据ThreadPoolExecutor的特点我们可以知道,最大的任务数为128+17,超过这个数量就会抛出RejectedExecutionException。在排队队列未满之前,最多有9个线程在运行,当排队队列满了之后,最多有17个线程在运行。

更多相关文章

  1. 浅谈Java中Collections.sort对List排序的两种方法
  2. Python list sort方法的具体使用
  3. python list.sort()根据多个关键字排序的方法实现
  4. Android面试题收集
  5. Android(安卓)SQLite系列
  6. Android(安卓)WebView 使用漏洞
  7. AndroidManifest.xml文件剖析 (二)
  8. Android(安卓)X库 BiometricPrompt 中 Crypto primitive not ini
  9. android关闭应用

随机推荐

  1. PHPMyWind教程:如何把本地测试好的程序发
  2. MySQL常用的函数
  3. 源码方式安装mysql5.5
  4. 数据库连接“Mysql”丢失,缺少mysql.sock
  5. MySQL查询优化技术讲座
  6. MYSQL简单的binlog恢复测试
  7. 如何从php中的数据库表创建表单下拉列表?
  8. 深入浅出MySQL读书笔记(一)
  9. MySQL搜索优化(用子查询替换长正则表达式)
  10. 阿里云服务器MySQL远程连接问题