AsyncTask 坑 AsyncTask对象多次执行

Posted zj510

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AsyncTask 坑 AsyncTask对象多次执行相关的知识,希望对你有一定的参考价值。

经常看到网上有这种面试题目:一个AsyncTask对象能不能被多次执行?

其实,想知道答案,最好的办法就是看文档说明,要是文档说不行那就是不行,行就是行。

如果想知道的更多,那就看代码呗。


AsyncTask的execute函数

excute是用来启动一个异步任务的API,先看看这个函数,

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

下面的这个函数里面可以看到有个成员mStatus,代码很简单,如果mStatus不是PENDING,直接丢异常。

    @MainThread
    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;
    

看看状态枚举,很简单就只有3种状态,PENDING, RUNNING, FINISHED。

   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,
    


看mStatus的变化流程:

1. AsyncTask对象创建的时候,初始化成PENDING.

    private volatile Status mStatus = Status.PENDING;

2. execute()里面会判断,如果不是pending(无论是running,还是finished)都直接丢出异常。只有pending才能往下走。当是pending的时候,就直接设置成running。然后就发onPreExecute通知和执行任务。

3. 执行完后,无论成功还是失败,都设置成finished。

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

从这些代码,其实就可以看出,一个AsyncTask对象被创建出来后,就只能执行一个异步任务。一旦开始执行了,无论在运行过程中,还是运行结束了,都不能在重复执行了。


FutureTask

之前也看到过,AsyncTask的构造函数里面,会创建一个mWorker和mFuture。mWorker会传给mFuture,mFuture里面的成员callable就是引用了mWorker对象。

然后FutureTask一次执行完后,就会调用下面的函数,很清楚callable被赋值为null了。

    private void finishCompletion() 
        // assert state > COMPLETING;
        for (WaitNode q; (q = waiters) != null;) 
            if (U.compareAndSwapObject(this, WAITERS, q, null)) 
                for (;;) 
                    Thread t = q.thread;
                    if (t != null) 
                        q.thread = null;
                        LockSupport.unpark(t);
                    
                    WaitNode next = q.next;
                    if (next == null)
                        break;
                    q.next = null; // unlink to help gc
                    q = next;
                
                break;
            
        

        done();

        callable = null;        // to reduce footprint
    

而mFuture和mWorker都是被声明称final的

    private final WorkerRunnable<Params, Result> mWorker;
    private final FutureTask<Result> mFuture;

那么当一个AsyncTask对象被创建出来后,mFuture和mWorker只能被初始化一次,而mFuture执行完一次任务后,就会调用finishCompletion,然后把callable赋值成0,也就是说就算后面再执行mFuture,因为callable被清0了,任务也不会再次执行。

从种种迹象表明,一个AsyncTask对象只能执行一次任务,是google刻意限制的。

至于为什么要设计成这样?

我想Google设计AsyncTask的初衷就是:这是个轻量级的类,用于执行简单的后台操作。

一个任务就是一个AsyncTask对象,如果想执行其他任务或者同个任务再执行一次,那就再创建一个AsyncTask对象呗。





以上是关于AsyncTask 坑 AsyncTask对象多次执行的主要内容,如果未能解决你的问题,请参考以下文章

AsyncTask 坑 多个task是串行执行还是并行的

AsyncTask 坑 哪些线程可以调用AsyncTask

AsyncTask 坑 多个task是串行执行还是并行的

AsyncTask 坑 多个task是串行执行还是并行的

在滚动侦听器上调用 asynctask 三次或多次在 listview 上滚动一次

AsyncTask使用及源码分析