2012-09-19 26 views
3

我的活動有一個AsyncTaskdoInBackground方法,你可以在下面看到。我必須向多個服務器發出多個搜索請求,爲了加速執行,我使用Java的ExecutorService來發出併發請求。當AsyncTask.cancel()方法被調用時,如何在AsyncTask中中斷Callables?

這工作得很好,但我想我AsyncTask停止正在執行的任何不幹,如果我叫了AsyncTask.cancel();truemayInterruptIfRunning參數。這在我需要在我的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; 

    } 
+0

我想'futFuture.get()'是要阻止用戶界面,對吧? –

+0

@Lalit Poptani:是嗎?我還沒有檢查過,但'futFuture.get()'阻塞似乎是合乎邏輯的。 –

+0

是的,我只是在YouTube上觀看Callable&Future的視頻,它說我會阻止UI,直到任務完成。這裏[是](https://www.youtube.com/watch?v=lnbWFV4b7M4) –

回答

3

我認爲一個解決辦法是檢查定期isCancelled()doInBackground()方法來檢查AsyncTask被取消,如果你需要停止你前面做的事情。

+0

這應該放在哪裏?看起來'Callables'只有在調用ExecutorService.invokeAll方法後纔會執行。在那之後就是我從中獲取'Callables'結果並追加到我的'List'的循環。我很困惑,因爲我看不到任何代碼在迭代中,並不斷等待「Callables」完成。這是從另一個線程'Acitivity'調用的另一個線程'AsyncTask'調用的一羣'Callables'。我甚至需要向「Callables」發送一箇中斷,以便中斷在整個鏈中傳播,但是怎麼做呢? –

+1

您可以在迭代「Future」列表時檢查。如果AsyncTask已經被取消,那麼你將在每個期貨的循環中調用'cancel()',關閉'ExecutorService'並返回'null' /'Collections.emptyList()'。 – Alex

+0

是的。這可以工作,但不會允許循環的一次迭代?這不會是一個「真正的」中斷。我想完成的是在AsyncTask.cancel方法被調用的時候通過調用ExecutorService.shutdown()來關閉ExecutorService,並立即終止ExecutorService的所有線程(Callables) 。這甚至有可能嗎? –

0

另一種選擇,如果例如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); 
} 

現在您可以從任何地方撥打取消。

1

這裏是你迭代,等待的地方:

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

對於未來,Waits if necessary for the computation to complete, and then retrieves its result. 您可以檢查isCancelled()這樣的get()方法,

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

@Alex,建議在下面做同樣的事情。看看我的評論,爲什麼我覺得這不會是一個「真正的」中斷的實現。 http://stackoverflow.com/questions/12489636/how-can-i-interrupt-callables-in-an-asynctask-when-the-asynctask-cancel-method#comment16806465_12489792 –

相關問題