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方法……

更多相关文章

  1. android加密、签名相关
  2. Android(安卓)判断一个url是否有效
  3. Android标题栏和状态栏显示与否的设置&&& Button或者ImageButton
  4. Android读取properties配置文件的实例详解
  5. android studio (mac) 快捷键
  6. 详解Android(安卓)getWidth和getMeasuredWidth
  7. Android(安卓)监听网络状态方法详解
  8. Android读取文本文件中内容的方法
  9. Android(安卓)apk安装的几种方法

随机推荐

  1. 安装 ADT 插件
  2. Ubuntu10.04安装JDK5
  3. Android权限 (代码区2)
  4. Android(安卓)NeedProxy
  5. Flutter Weekly Issue 61
  6. Install Android(安卓)NDK No.1
  7. android GridView条目点击变色
  8. 设置网络首选项
  9. Android软件加安全码
  10. android 加载recyclerView的popupWindow