【问题标题】:How can I interrupt Callables in an AsyncTask when the AsyncTask.cancel() method is invoked?调用 AsyncTask.cancel() 方法时,如何中断 AsyncTask 中的 Callables?
【发布时间】:2012-09-19 06:38:29
【问题描述】:

我的活动有一个AsyncTask,您可以在下面看到其doInBackground 方法。我必须向多个服务器发出多个搜索请求,为了加快执行速度,我使用了 Java 的 ExecutorService 来发出并发请求。

这工作正常,但我希望我的AsyncTask 停止它正在做的任何事情并退出,如果我用true 作为mayInterruptIfRunning 参数调用AsyncTask.cancel(); 方法。这在我需要在我的Activity 退出时停止任务的情况下很有用,例如按下“返回”按钮。

我读过调用AsyncTaskcancel() 方法将阻止onPostExecute 方法被调用,但doInBackground 将一直运行直到它完成。

有没有办法,我可以打断我的Callables 并强迫他们停止正在做的事情并停止AsyncTask

为简洁起见,我在此处发布了我的代码的删节版本,但我有一堆 Callables,而不仅仅是一个。

谢谢。

  protected ArrayList<Result> doInBackground(final String... strQuery) {

      ArrayList<Result> objResults = new ArrayList<Result>();
      ExecutorService esrExecutor = Executors.newFixedThreadPool(2);
      Set<Callable<ArrayList<Result>>> setCallables = new HashSet<Callable<ArrayList<Result>>>();

      setCallables.add(new Callable<ArrayList<Result>>() {

          public ArrayList<Result> call() throws Exception {

              try {

                  MySearcher objSearcher = new MySearcher(Finder.this.objContext);
                  ArrayList<Result> objResults = new ArrayList<Result>();

                  objResults = objSearcher.doSearch(strQuery[0]);

                  return objResults;

              } catch (Indexer.LoginException e) {
                  return null;
              }

              return null;

          }

      });


      List<Future<ArrayList<Result>>> lstFutures;

      try {

          lstFutures = esrExecutor.invokeAll(setCallables);

          for(Future<ArrayList<Result>> futFuture : lstFutures){
              if (futFuture.get().isEmpty() == false)
                  objResults.addAll(futFuture.get());
          }

      } catch (InterruptedException e) {
          e.printStackTrace();
      } catch (ExecutionException e) {
          e.printStackTrace();
      }

      esrExecutor.shutdown();

      return objResults;

  }

【问题讨论】:

  • 我认为futFuture.get() 会屏蔽用户界面,对吧?
  • @Lalit Poptani:是这样吗?我还没有检查过,但futFuture.get() 阻塞似乎是合乎逻辑的。
  • 是的,我只是在 youtube 上观看 Callable & Future 的视频,它说我将阻止 UI,直到任务完成。这里it is
  • 我会坚持使用 AsyncTask 并从那里返回值。你可以查看我的回答here

标签: java android android-asynctask interrupt executorservice


【解决方案1】:

我认为一种解决方案是定期在您的 doInBackground() 方法中检查 isCancelled() 以检查 AsyncTask 是否已取消以及您是否需要更早停止正在执行的操作。

【讨论】:

  • 这个应该放在哪里?似乎在调用 ExecutorService.invokeAll 方法之前不会执行 Callables。紧随其后的是我从Callables 获取结果并附加到我的List 的循环。我很困惑,因为我看不到任何我迭代并不断等待Callables 完成的代码。这是一组从另一个线程AsyncTask 调用的Callables,从另一个线程Acitivity 调用。我什至需要向Callables 发送中断,以便中断在整个链中传播,但是如何?
  • 您可以在遍历Future 列表时进行检查。如果 AsyncTask 已被取消,那么您将在每个期货中断循环时调用 cancel(),关闭 ExecutorService 并返回 null/Collections.emptyList()
  • 是的。那可以工作,但那仍然不允许循环的一次迭代吗?这不会是一个“真正的”中断。我想要完成的是通过在调用AsyncTask.cancel 方法时调用ExecutorService.shutdown() 来关闭ExecutorService,并立即杀死ExecutorService 的所有线程(Callables)。这甚至可能吗?
  • 通常如果你在 asynTask 上调用cancel(true) 那么isCancelled() 方法应该直接响应true。因此,您是否会进行循环迭代取决于doInBackground 开始和调用取消方法之间经过的时间。我不知道在AsyncTask 上调用cancel 时有效关闭ExecutorService 的方法。签入doInBackground 是我要做的事情
【解决方案2】:

这里是你迭代和等待的地方:

   for(Future<ArrayList<Result>> futFuture : lstFutures){
          if (futFuture.get().isEmpty() == false)
              objResults.addAll(futFuture.get());
      }

Future 的get() 方法,Waits if necessary for the computation to complete, and then retrieves its result. 你可以像这样检查isCancelled()

       for(Future<ArrayList<Result>> futFuture : lstFutures){
           if(isCancelled())
              break;
           else if (futFuture.get().isEmpty() == false)
              objResults.addAll(futFuture.get());
      }
      if(isCancelled())esrExecutor.shutdownNow();

【讨论】:

【解决方案3】:

另一种选择,例如,如果doSearch 有一个循环,您可以手动执行,而无需使用isCancelledcancel。您的 MySearcher 类可能具有以下内容。

//in your MySearcher class
private AtomicBoolean cancelled = false;

public ArrayList<Result> doSearch(...){
    while(notFound && !cancelled.get()){
     // keep searching
    }
}

public void cancel(){
    cancelled.set(true);
}

现在您可以从任何地方调用取消。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-31
    • 1970-01-01
    • 1970-01-01
    • 2016-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-06
    相关资源
    最近更新 更多