AsyncTask的简单介绍

作为Google工程师推荐的执行异步任务首选的类,AsyncTask内部使用了线程池来进行工作任务的执行。首先看一下类中的几个属性:

     /**
     * 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);

    /**
     * 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();
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

可以看到,默认的时候,AsyncTask使用的执行器是SERIAL_EXECUTOR。看一下SerialExecutor的源码:

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是一个内部类,直接实现Executor接口,重写接口中的抽象方法execute。可以看到它的实现逻辑非常简单但是比较巧妙,首先将参数中的Runnable对象进行二次封装压入一个阻塞队列中,然后在THREAD_POOL_EXECUTOR这个执行器中执行。二次封装的目的就是保证,只有一个Runnable执行完毕以后,才会去执行阻塞队列中的下一个Runnable。如果阻塞队列中的内容取完了,就不继续执行了,等待下一次有任务压入再继续执行。

THREAD_POOL_EXECUTOR是一个标准的线程池。AsyncTask中直接使用了ThreadPoolExecutor构造器来进行构建,而没有使用Executors的工具方法。看一下ThreadPoolExecutor的构造器说明:

public ThreadPoolExecutor(int corePoolSize,
                       int maximumPoolSize,
                       long keepAliveTime,
                       TimeUnit unit,
                       BlockingQueue<Runnable> workQueue,
                       ThreadFactory threadFactory)

其中各个参数的含义是:

*@param corePoolSize the number ofthreads to keep in the pool, even

    *        if they are idle, unless{@code allowCoreThreadTimeOut} is set

    * @param maximumPoolSize the maximum numberof threads to allow in the

    *        pool

    * @param keepAliveTime when the number ofthreads is greater than

    *        the core, this is themaximum time that excess idle threads

    *        will wait for new tasksbefore terminating.

    * @param unit the time unit for the{@code keepAliveTime} argument

    * @param workQueue the queue to use forholding tasks before they are

    *        executed.  This queue will hold only the {@codeRunnable}

    *        tasks submitted by the {@codeexecute} method.

    * @param threadFactory the factory to usewhen the executor

    *        creates a new thread

AsyncTask中的THREAD_POOL_EXECUTOR是这样创建的:

new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

其中:

private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final int KEEP_ALIVE = 1;
private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(10);
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());
        }
};

所以,AsyncTask中的线程池是一个有5条执行线程,最多扩容到128线程(闲置1秒回收)的线程池,线程池中的每一个工作线程通过sThreadFactory创建(这个工厂的作用就是为每一条新建的线程指定一个名字),而这些线程准备执行的任务都放在了sPoolWorkQueue阻塞队列中,这个队列最多一次性存放10个任务。

接下来再看几个AsyncTask中的方法:

execute方法:

execute(Runnable runnable)/execute(Params... params)

execute(Runnable runnable)的源代码是:

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

可以看到这里就是调用sDefaultExecutor的execute方法,而默认的时候sDefaultExecutor就是上面分析过的SerialExecutor对象。

重载版本是使用了可变参数和泛型的execute(Params... params),它的源代码是:

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

此时会去调用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();
        mWorker.mParams = params;
        exec.execute(mFuture);
        return this;
    }

这里有几个地方需要的是:

1)executeOnExecutor是一个public的方法,它可以传入一个执行器作为参数,并且方法体内最终回去调用执行器来执行任务。这就意味着,可以创建了AsyncTask对象后,不去调用execute方法(调用execute方法,会使用sDefaultExecutor作为参数传入executeOnExecutor方法),而是显式的调用executeOnExecutor并传入自己的执行器(使用Executros工具类或者自行实现Executor接口)。

2)在该方法中会去调用onPreExecute();随后执行执行器的execute方法。

3)mFuture是一个FutureTask对象,FutureTask继承自RunnableFuture接口,而 RunnableFuture接口又继承自Runnable和 Future接口。因此这里mFuture以一个Runnable的身份被传入了执行器的execute方法。FutureTask被线程池驱动执行Callable任务,任务完成后通过handler提交结果。

4)这里还有2个重要的属性mWorker和mFuture。这两个属性都是在调用AsyncTask构造器时进行初始化的,看一下源代码:

public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                return postResult(doInBackground(mParams));
            }
        };
        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);
                }
            }
        };
}

首先是mWorker,它是一个WorkerRunnable的对象,而WorkerRunnable是一个内部抽象类:

private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
        Params[] mParams;
}

它试图实现Callable接口。

因此在创建mWorker的时候,用一个匿名内部类实现了抽象类WorkerRunnable,重写了Callable的call方法:

mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                return postResult(doInBackground(mParams));
            }
        };

call方法就是会设置mTaskInvoked属性的值为true,然后以标准的后台线程优先级准备执行任务。postResult方法的源代码是:

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

作用很明显,将doInBackground(mParams)返回值一方面作为消息的obj提交出去,同时也将它作为返回值返回。

随后mWorker作为参数以Callable的身份传入FutureTask构造器创建mFuture对象。FutureTask对象创建并在自身的run方法中调用mWorker的call方法获得返回值,这个返回值将被设为mFuture的outcome属性的值。在创建mFuture的时候,重写了FutureTask的done方法,这个方法在Callable的call方法执行结束,mFuture被设定了结果后回调。done方法的作用就是保证得将doInBackGround方法的返回值提交出去。

在postResult方法中有一个sHandler,sHandler是AsyncTask的一个属性,声明时即创建了对象:

private static final InternalHandler sHandler = new InternalHandler();
InternalHandler是另一个内部类:
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;
            }
        }
}

另外在发送消息的时候,将doInBackground返回值会封装为一个AsyncTaskResult,这个类是另一个内部类:

private static class AsyncTaskResult<Data> {
        final AsyncTask mTask;
        final Data[] mData;
        AsyncTaskResult(AsyncTask task, Data... data) {
            mTask = task;
            mData = data;
        }
}

在sHandler中处理结果时使用了AsyncTaskResult中mTask的finish方法。这实际就是AsyncTask的finish方法:

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

在finish方法里面调用了onPostExecute方法。

总体来说,AsyncTask的execute方法要不然利用线程池去驱动Runnable对象,要不然用线程池去驱动FutureTask对象。顺道这里再小贴士一下Runnable,Callable和FutureTask:

使用Runnable时:无法获得返回值

使用Callable时:无法在线程中(new Thread(Runnable r))使用,Thread类只支持Runnable,只能使用ExecutorService来驱动Callable。

FutureTask通过实现RunnableFuture接口,同时实现了Runnable和Future,所以兼顾两者优点,既可以使用ExecutorService,也可以使用Thread。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值