AsyncTask源码阅读

  AsyncTask是Android系统封装的多线程工具类。它管理着线程池,控制着合理的执行中的线程的个数。同时,它还提供了,执行前,执行中,执行后的接口,方便线程的管理与使用。

  下面,我们来阅读一下AsyncTask的源码,才疏学浅,不能多么深刻的理解,但相信在阅读过程中,能有一些意想不到的收获。

  

public abstract class AsyncTask<Params, Progress, Result> {
    private static final String LOG_TAG = "AsyncTask";

    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<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);

  首先,我们可以看到,AsyncTask是一个虚类。成员变量非常多,我们一个一个来认识。

  LOG_TAG没什么好说的。

  CPU_COUNT顾名思义就是当前设备的CPU数量。其中Runtime是让app获取虚拟机运行环境的类,不能直接创建,但可以获取它的引用。我们从中取得可用的处理器有多少。

  接下来的CORE_POOL_SIZE和MAXIMUM_POOL_SIZE即是核心线程数和最大线程数。

  KEEP_ALIVE在ThreadPoolExecutor中有所描述:keepAliveTime when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating。

  然后,是一个静态私有的线程工厂。它负责新建线程,其中mCount 是一个原子Integer。虽然没看后面,但我猜想,由于线程工厂sThreadFactory是静态的,可能会有多个线程来读写这个sThreadFactory.mCount因此,它需要是一个线程安全的原子数。getAndIncrement()是后置递增的方法,效果类似于i++,但它本身是线程安全的,而i++不是线程安全的。通过newThread方法,sThreadFactory即新建了以当前已有线程数为名字的新线程。

  sPoolWorkQueue是一个BlockingQueue(阻塞队列)。即如果队列为空,我的取操作将会被阻塞,直到有元素进入队列为止;如果队列为满,我的写入操作将会被阻塞,直接有元素被取走留出空位为止。其他的则和基本队列一样,遵循FIFO原则。而LinkedBlockingQueue则是在构造方法中可以很方便的确定它的长度。这个作为正在工作的线程队列是一个很合适的数据结构。

 

    public static final Executor SERIAL_EXECUTOR = new 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);
            }
        }
    }

 

  接下来,AsyncTask定义了一个特殊的Executor并创建了它的实例。看看这个类,我们就会发现,其中有一个容器叫ArrayDeque,用来存放我们的任务。

    它是一个可以调整大小的双端队列

  数组双端队列没有容量限制,使他们增长为必要支持使用。

  它们不是线程安全的;如果没有外部同步。

  不支持多线程并发访问。

  null元素被禁止使用在数组deques。

  它们要比堆栈Stack和LinkedList快。mTasks.offe()的主要作用是从双端队列的尾部insert元素,而mTasks.poll()的作用是从双端队列头部取出元素。

  有了以上补充知识,现在我们来看看这个类到底是如何工作的。当执行器执行任务时,首先,我们将一个新的Runnable推入任务队列中。如果任务当前活动任务为空则执行scheduleNext()方法,执行队列中的下一个任务。在scheduleNext()方法中,我们可以看到代码先从mTasks中poll出队首的任务,如果不为空,则让线程池去执行它。执行的过程是先执行任务本身的工作(即r.run()),执行完成后,执行scheduleNext()去寻找下一个任务。

 

    private static final int MESSAGE_POST_RESULT = 0x1;
    private static final int MESSAGE_POST_PROGRESS = 0x2;

    private static final InternalHandler sHandler = new InternalHandler();

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    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;
            }
        }
    }

  这里定义了一个handler,用于接收进行中的线程发回来的消息。主要接收其他线程完成,和其他线程进度通知两类消息。

  我们先来看看AsyncTaskResult类

    @SuppressWarnings({"RawUseOfParameterizedType"})
    private static class AsyncTaskResult<Data> {
        final AsyncTask mTask;
        final Data[] mData;

        AsyncTaskResult(AsyncTask task, Data... data) {
            mTask = task;
            mData = data;
        }
    }

  AsyncTaskResult中有两个成员,一个是AsyncTaskResult封装的任务,另一个Data应该是任务的进度。

  result.mTask.finish(result.mData[0])的代码:

  

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

 

  任务在取消或结束时会有这样两个方法。方法本身内容是空的,我们可以继承AsyncTask,重写这两个方法满足业务逻辑。

 

   private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    private final WorkerRunnable<Params, Result> mWorker;
    private final FutureTask<Result> mFuture;

  FutureTask 

  一个可取消的异步运算,这个类实现了Fututre的接口,可以开始和取消一个运算操作,判断这个操作是否已经完成了,和重新得到运算操作的结果。运算的结果仅仅在运算结束完成后被恢复,get的方法将会阻塞程序,如果这个运算操作还没有完成的话。一旦运算操作完成了,这个操作就不能重新开始或者取消了。

  这个类过去常常用于包装一个Callable or Runnable 类的。因为FutureTask实现了runnable借口,一个FutureTask可以实现线程池中的execution方法。

除了是一个单独的类之外,这个类还提供了可能有之用途定制任务classed的保护功能.

  

    private final AtomicBoolean mCancelled = new AtomicBoolean();
    private final AtomicBoolean mTaskInvoked = new AtomicBoolean();

  接下面就是两个线程安全的Boolean型,记录任务是否已被取消和任务是否已被调用,两个状态。

    /**
     * Indicates the current status of the task. Each status will be set only once
     * during the lifetime of a task.
     */
    public enum Status {
        /**
         * Indicates that the task has not been executed yet.
         */
        PENDING,
        /**
         * Indicates that the task is running.
         */
        RUNNING,
        /**
         * Indicates that {@link AsyncTask#onPostExecute} has finished.
         */
        FINISHED,
    }

  这里一个枚举型,用来区分任务的状态,未开始、已开始、已完成。

  

  以上AsyncTask的成员变量就阅读完毕。接下来,开始看AsyncTask中的方法。

 

    /** @hide Used to force static handler to be created. */
    public static void init() {
        sHandler.getLooper();
    }

    /** @hide */
    public static void setDefaultExecutor(Executor exec) {
        sDefaultExecutor = exec;
    }

  前两个方法比较简单易懂。用@hide做了标记,即外部不可调用,只在内部进行的一些初始化。

  接下来,我们将开始阅读AsyncTask的构造方法。代码不多,却非常重要。

    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    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);
                }
            }
        };
    }

  这个方法从整体上来看,就是创建了WorkerRunnable和FutureTask两个类的对象。我们先来看WorkerRunnable类的创建:  

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

 

  上面提到WorkerRunnable类满足了Callable的接口,程序在这里实现了它的call方法。先将任务被调用的标志位设为true,然后将当前线程设为后台线程。doInBackground是个虚方法,没有具体实现,交由子类去实现,使用过AsyncTask的都无需多说这一点,将doInBackground的结果给处理结果的方法postResult(Result r),我们来看看postResult(Result r)的实现。  

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

 

   代码会用Result建一个AsyncTaskResult对象,将任务和数据保存在一起,然后作为结果用message发送给sHandler。sHandler前面介绍过是一个将任务执行的进度或结果返回的类。以上WorkerRunnable就创建完成了。接下来再看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);
                }
            }
        };

 

   postResultIfNotInvoked()方法和postResult()方法几乎一样,只是在调用前,检查了mTaskInvoked的值。如果任务被取消,则会将result设为null。

  接下来看到一个常用的方法

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

 

  由于语义化命名,我们非常容易理解,这个方法,即是取消任务。需要传入一个boolean值,表示,如果它正在运行,是否需要中断。

  后面有一些简单的方法比如isCancelled(),就是取前面介绍的mCancelled的值,在此就不赘述了。我们接下来看最核心的方法。execute();

  

     /* <p>This method must be invoked on the UI thread.
     *
     * @param params The parameters of the task.
     *
     * @return This instance of AsyncTask.
     *
     * @throws IllegalStateException If {@link #getStatus()} returns either
     *         {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
     *
     * @see #executeOnExecutor(java.util.concurrent.Executor, Object[])
     * @see #execute(Runnable)
     */
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

 

  

  

     /* <p>This method must be invoked on the UI thread.
     *
     * @param exec The executor to use.  {@link #THREAD_POOL_EXECUTOR} is available as a
     *              convenient process-wide thread pool for tasks that are loosely coupled.
     * @param params The parameters of the task.
     *
     * @return This instance of AsyncTask.
     *
     * @throws IllegalStateException If {@link #getStatus()} returns either
     *         {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
     *
     * @see #execute(Object[])
     */
    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;
    }

 

  方法先做了一个判断,如果任务不是未执行状态,根据任务当前的状态,抛出异常。之后将当前的任务状态改为正在运行,执行 onPreExecute();这个空方法,并将参数传给mWorker,由默认的执行器执行。默认执行器SerialExecutor执行这个任务。这又回到了SerialExecutor的初始化,里面包含了执行任务的方法,这个在前面已经介绍过了。

  到这里,AsyncTask类的基本流程就阅读完毕了。但是里面还有一些类的工作原理不是特别清楚如FutureTask等,有待探究。

  Done!

 

转载于:https://www.cnblogs.com/fishbone-lsy/p/5068444.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值