AsyncTask取消了像HttpGet这样的长时间运行操作

时间:2013-02-27 23:21:45

标签: android android-asynctask

我见过几个关于取消AsynTask的other post,但我认为其中任何一个都没有解决问题。想象一下这种情况:

public class TestTask extends AsyncTask<Void, Void, Object> {

@Override
protected void onCancelled(Object result) {
    running = false;
    Log.i("Test", "onCancelled");
}

@Override
protected Object doInBackground(Void... params) {
        try {
            Log.i("Test", "cancelling");
            cancel(true);
            Thread.sleep(5000);
            Log.i("Test", "Past sleep");
        } catch (InterruptedException e) {
            Log.i("Test", "InterruptedException", e);
        }

    return null;
}

}

想象一下,我想在下载过程中取消这个长达20秒的请求,例如,如果服务器对json请求的响应速度很慢。所以Thread.sleep(5000)可能是我要取消的HttpGet请求。但是,cancel方法被标记为final,所以我无法覆盖它并调用get.abort()。 onCancel挂钩发生在doInBackground之后并返回UI线程。一旦HttpGet请求开始,检查isCancel对我没有任何好处。

我解决这个问题的方法是在我的AsynTask上创建一个abort()方法并调用它。

public void abort() {
   get.abort();
   cancel(true);
}

但这似乎与Android谷物有点不同。有没有更好的方法来取消请求?

2 个答案:

答案 0 :(得分:0)

docs for HttpGet中,没有提及线程安全性,因此以您描述的方式调用abort()可能会导致意外结果(充其量)。您可以做的是在HttpGet的构造函数中传递AsyncTask对象,或者通过设置器传递(只要您在调用AsyncTask.execute()之前执行此操作)。

如果任务已被取消,您必须定期检查doInBackground()内部:

@Override
protected Object doInBackground(Void... params) {
        // start GET request
        try {
            Log.i("Test", "cancelling");
            cancel(true);
            Thread.sleep(5000);
            Log.i("Test", "Past sleep");

            if ( this.isCancelled() ) {
               // abort GET request and/or stop doing other work
               return null;
            }
            else {
                // do what ever work you need to
            }
        } catch (InterruptedException e) {
            Log.i("Test", "InterruptedException", e);
        }

    return null;
}

Source

每当您觉得应该停止任务时,您都可以随时致电AsyncTask.cancel(true)

答案 1 :(得分:0)

我不确定这是否适用,但您可以使用执行下载任务的执行程序服务创建另一个线程,并继续检查isCancelled()内的doInBackground()或直到将来的对象返回,以先发生者为准:

@Override
protected Object doInBackground(Void... params)
{
    Callable<Void> downlaodTask = new Callable<Void>()
    {
        @Override
        public Void call() throws Exception
        {
            // download task here

            return null;
        }
    };

    ExecutorService executor = Executors.newSingleThreadExecutor();
    Future<Void> future = executor.submit(downlaodTask);

    while(true) // check every second
    {
        try
        {
            future.get(1, TimeUnit.SECONDS); // wait until the download task finishes with 1 second as a timeout
            break;
        }
        catch(TimeoutException e)
        {
            if(isCancelled())
            {
                executor.shutdownNow(); // or abort() or both
                break;
            }
        }
    }

    return null;
}