Android之AsyncTask源码分析(第五篇:execute方法只能执行一次的原因)

0、当你调用AsyncTask对象的execute()方法时,突然发生崩溃………………内心充满了不解,它抛出异常:java.lang.IllegalStateException: Cannot execute task: the task has already been executed (a task can be executed only once)

为什么会这样呢????????????

07-09 23:30:11.085 23377-23377/com.xx.cheez E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.xx.cheez, PID: 23377
    java.lang.IllegalStateException: Cannot execute task: the task has already been executed (a task can be executed only once)
        at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:640)
        at android.os.AsyncTask.execute(AsyncTask.java:595)
        at com.wp.cheez.activity.FillSpaceActivity$MyBtnClickLis.onClick(FillSpaceActivity.java:60)
        at android.view.View.performClick(View.java:6891)
        at android.widget.TextView.performClick(TextView.java:12651)
        at android.view.View$PerformClick.run(View.java:26083)
        at android.os.Handler.handleCallback(Handler.java:789)
        at android.os.Handler.dispatchMessage(Handler.java:98)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6938)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)

        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

 

1、从上面的线程堆栈找到AsyncTask的源码

    @MainThread
    public final AsyncTask execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params); //此处为595行
    }

上面的堆栈明确说明execute方法位于AsyncTask类的595行

 

2、595行执行的是executeOnExecutor方法,让我们去看看executeOnExecutor方法里面又干了什么?在executeOnExecutor方法中找到了抛出异常对象的地方,请看下面代码中的注释

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

 

3、发现AsyncTask的mStatus == RUNNING的时候,executeOnExecutor()方法会抛出java.lang.IllegalStateException: Cannot execute task: the task has already been executed..……此处省略好多字,让我们再看下关键代码,注意注释

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

 

4、那么AsyncTask对象持有的mStatus什么时候会等于RUNNING呢?此时需要去找一下mStatus是在哪个位置被赋值为RUNNING的!!!

首先发现mStatus的初始值是Status.PENDING,而且还加了volatile,保证共享变量mStatus的可见性与有序性(一个线程写入该共享变量,另一个线程一定能读到它的最新值,并且volatile会禁止编译器与处理器的重排序)

private volatile Status mStatus = Status.PENDING;

 

5、那么第4条中提到的Status.PEDING又是什么呢???

AsyncTask类定义了一个称做Status的内部枚举类,它专门用于标记AsyncTask对象的状态,可以看到一共有三个状态

PENDING  代表准备状态

RUNNING 代表运行状态

FINISHED  代表完成状态

public enum Status {
   
        PENDING,
        
        RUNNING,
        
        FINISHED,
    }

 

6、继续寻找mStatus什么时候被赋值为RUNNING的

在整个AsyncTask类中只有一处为mStatus赋值为RUNNING,那就是在executeOnExecutor方法中……

    @MainThread
    public final AsyncTask executeOnExecutor(Executor exec,
            Params... params) {
        
        ........

        mStatus = Status.RUNNING;   //看这里

        ........

        return this;
    }

 

7、答案明确了

一个AsyncTask对象,它的execute方法只能调用一次!再次调用execute方法时,内部调用的executeOnExecutor方法有一个判断逻辑,会根据mStatus的状态抛出一个IllegalStateException对象

当mStatus的状态为RUNNING或FINISHED时,都会抛出异常

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

 

8、重温下mStatus在AsyncTask对象生命周期内的状态变化(下面都是mStatus仅有的赋值代码)

调用execute方法前,mStatus的状态为PENDING(AsyncTask对象创建阶段赋值)

    private volatile Status mStatus = Status.PENDING;

调用execute方法后,mStatus的状态更新为RUNNING(executeOnExecutor方法中赋值)

        mStatus = Status.RUNNING;

所有AsyncTask的任务执行完成后,mSatus的状态又变为FINISHED(finish方法中赋值)

        mStatus = Status.FINISHED;

 

7、解决办法

想再执行一个任务怎么办??

答:再new一个AsyncTask对象,再次调用execute方法……

你可能感兴趣的:(Android,综合)