多次执行AsyncTask

时间:2011-06-16 14:47:09

标签: android android-asynctask

在我的Activity中,我使用了一个从AsyncTask扩展的类和一个AsyncTask实例的参数。当我打电话给mInstanceOfAT.execute("")时,一切都很好。 但是当我按下再次调用AsyncTask的更新按钮时应用程序崩溃(如果网络作业不起作用)。然后出现一个例外情况

  

无法执行任务:任务有   已被执行(任务可以   只执行一次)

我试过为Asyctask的实例调用cancel(true),但它也不起作用。到目前为止唯一的解决方案是创建Asyntask的新实例。这是正确的方法吗?

感谢。

5 个答案:

答案 0 :(得分:216)

AsyncTask个实例只能使用一次。

相反,只需将您的任务称为new MyAsyncTask().execute("");

即可

来自AsyncTask API文档:

线程规则

此类必须遵循一些线程规则才能正常工作:

  • 必须在UI线程上创建任务实例。
  • 必须在UI线程上调用
  • execute(Params ...)。
  • 不要手动调用onPreExecute(),onPostExecute(Result),doInBackground(Params ...),onProgressUpdate(Progress ...)。
  • 任务只能执行一次(如果尝试第二次执行,则会抛出异常。)

答案 1 :(得分:28)

在Steve Prentice的回答中详细说明了ASyncTask发生故障的实例,但是,当您执行ASyncTask 多少次时,您可以自由地执行在线程运行时你喜欢什么...

将可执行代码放在 doInBackground()中的循环中,并使用并发锁来触发每次执行。您可以使用 publishProgress()/ onProgressUpdate()检索结果。

示例:

class GetDataFromServerTask extends AsyncTask<Input, Result, Void> {

    private final ReentrantLock lock = new ReentrantLock();
    private final Condition tryAgain = lock.newCondition();
    private volatile boolean finished = false;

    @Override
    protected Void doInBackground(Input... params) {

        lock.lockInterruptibly();

        do { 
            // This is the bulk of our task, request the data, and put in "result"
            Result result = ....

            // Return it to the activity thread using publishProgress()
            publishProgress(result);

            // At the end, we acquire a lock that will delay
            // the next execution until runAgain() is called..
            tryAgain.await();

        } while(!finished);

        lock.unlock();
    }

    @Override
    protected void onProgressUpdate(Result... result) 
    {
        // Treat this like onPostExecute(), do something with result

        // This is an example...
        if (result != whatWeWant && userWantsToTryAgain()) {
            runAgain();
        }
    }

    public void runAgain() {
        // Call this to request data from the server again
        tryAgain.signal();
    }

    public void terminateTask() {
        // The task will only finish when we call this method
        finished = true;
        lock.unlock();
    }

    @Override
    protected void onCancelled() {
        // Make sure we clean up if the task is killed
        terminateTask();
    }
}

当然,这比传统的ASyncTask使用稍微复杂一点,并且您放弃使用 publishProgress()进行实际的进度报告。但是如果您关心内存,那么这种方法将确保在运行时只有一个ASyncTask保留在堆中。

答案 2 :(得分:2)

我有同样的问题。在我的情况下,我有一个我想在onCreate()onResume(中完成的任务。所以我使我的Asynctask静态,并从中获取实例。现在我们仍然有同样的问题。

所以我在onPostExecute()中做的是:

instance = null;

请记住我在静态getInstance方法中检查我的实例不为null,否则我创建它:

if (instance == null){
    instance = new Task();
}
return instance;

postExecute中的方法将清空实例并重新创建它。当然这可以在课外完成。

答案 3 :(得分:1)

我已将旋转任务设置为静态,然后帮助我在旋转更改时附加,分离并重新连接到UI线程。但是回到你的问题,我所做的是创建一个标志来查看线程是否正在运行。如果要重新启动线程,我会检查旋转任务是否正在运行,如果它是我举报警告。如果不是,我将其设为null然后创建一个新的,它将解决您看到的错误。此外,成功完成后,我将完成的旋转感知任务归零,以便它可以再次运行。

答案 4 :(得分:0)

是的,这是真的,医生说只能执行一个Asyntask。

每次你需要使用它时,你必须实例:

// Any time if you need to call her
final FirmwareDownload fDownload = new FirmwareDownload();
fDownload.execute("your parameter");

static class FirmwareDownload extends AsyncTask<String, String, String> {
}