一段时间后取消异步任务

2022-09-03 14:17:24

这可能是一个重复的问题,但我没有找到我想要的东西。我在UI活动中调用AsyncTask,在doInBackground中,我调用了一个需要时间的方法。如果一段时间后数据未返回,我想中断此线程。下面是我尝试执行此操作的代码。new LoadData().execute();

class LoadData extends AsyncTask<String, String, String>
{
    @Override
    protected void onPreExecute() {
    super.onPreExecute();
    startTime = System.currentTimeMillis();
    }
    protected String doInBackground(String... args)
    {

        DataCollector dc = new DataCollector();
        data = dc.collectData(query);
        //Here I check if the time is greater than 30 seconds then cancel
        if(((System.currentTimeMillis()-startTime)/1000)>30)
        {
           cancel(true);
        }
    return null;
    }
}

但这并不能阻止30秒后的任务,实际上它需要更多的时间。我也尝试过,但这也不起作用。get(long timeout, TimeUnit unit);

任何人都可以向我展示我该怎么做,或者我如何在doInBackground中使用isCancelled()。

谢谢。


答案 1

您需要一个在一定时间后取消任务的线程。该线程可能如下所示:

public class TaskCanceler implements Runnable{
    private AsyncTask task;

    public TaskCanceler(AsyncTask task) {
        this.task = task;
    }

     @Override
     public void run() {
        if (task.getStatus() == AsyncTask.Status.RUNNING )
            task.cancel(true);
     }
}

当您调用 AsyncTask 时,您需要在一定时间(=超时,在本例中为 20 秒)后运行 cancle 任务。

private Handler handler = new Handler();
private TaskCanceler taskCanceler;
...
LoadData task = new LoadData();
taskCanceler = new TaskCanceler(task);
handler.postDelayed(taskCanceler, 20*1000);
task.execute(...)

如果你在取消或完成时清理它,这是一个好主意

if(taskCanceler != null && handler != null) {
     handler.removeCallbacks(taskCanceler);
}

当然,您可以将其包装在 AsyncTask 的自定义实现中。我已经多次使用这种模式,它就像一个魅力。需要注意的一点是,在极少数情况下,处理程序不会启动,我怀疑如果您在错误的上下文中创建它,它在某些情况下将无法生存,因此我强制处理程序成为具有handler= new Handler(Looper.getMainLooper());


答案 2

您必须在其他线程上执行时间检查。

您目前要做的是:执行(在后台),一旦准备就绪,您检查是否应该取消。因此,如果查询需要1分钟,您将在1分钟后进行取消检查,这已经为时已晚。dc.collectData(query)

您可以做的是计划一个计时器任务,该计时器任务应在 LoadData().execute() 后 30 秒运行,如果计时器任务已运行,则可以取消 AsyncTask(如果它仍在运行)


推荐