0

我看过其他几篇关于取消 AsynTask 的帖子,但我认为它们中的任何一个都不能解决问题。想象一下这个场景:

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 请求。但是,取消方法被标记为最终方法,因此我无法覆盖它并调用 get.abort()。onCancel 钩子发生在 doInBackground 之后并返回 UI 线程。一旦 HttpGet 请求开始,检查 isCancel 对我没有任何好处。

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

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

但这似乎有点违背Android的原则。有没有更好的方法来取消请求?

4

2 回答 2

0

在 的文档中HttpGet,没有提及线程安全,因此调用abort()您描述的方式可能会导致不希望的结果(充其量)。你可以做的是HttpGet在你的构造函数中传递一个对象AsyncTask,或者通过一个setter(只要你在调用之前这样做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;
}

来源

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

于 2013-03-01T22:24:00.993 回答
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;
}
于 2013-03-01T22:34:38.670 回答