Android - 強力取消AsyncTask


Answers

AsyncTask上調用cancel() 。 這是否會取消任何事情取決於你在做什麼。 引用Romain Guy:

如果你調用cancel(true),一個中斷將被發送到後台線程,這可能有助於中斷任務。 否則,您應該確保在doInBackground()方法中定期檢查isCancelled()。 您可以通過code.google.com/p/shelves查看相關示例。

Question

我在我的一個活動中實現了AsyncTask:

 performBackgroundTask asyncTask = new performBackgroundTask();
 asyncTask.execute();

現在,我需要實現“取消”按鈕功能,所以我必須停止執行正在運行的任務。 我不知道如何停止正在運行的任務(後台任務)。

所以請建議我,我如何強制取消AsyncTask?

更新:

我發現了相同的Cancel()方法,但我發現調用cancel(boolean mayInterruptIfRunning)並不一定會停止後台進程的執行。 所有似乎發生的事情是,AsyncTask將執行onCancelled(),並且在完成時不會運行onPostExecute()。




在評論case中提到的isCancelled() always returns false even i call asynctask.cancel(true); 如果關閉我的應用程序是特別有害的,但AsyncTask會繼續工作。

為了解決這個問題,我按照以下方式修改了Jacob Nordfalk代碼提出的建議:

protected Object doInBackground(Object... x) {
    while (/* condition */) {
      // work...
      if (isCancelled() || (FlagCancelled == true)) break;
    }
    return null;
 }

並將以下內容添加到主要活動中:

@Override
protected void onStop() {
    FlagCancelled = true;
    super.onStop();
}

由於我的AsyncTask是其中一個視圖的私有類,所以標誌的獲取者或設置者必須通知AsyncTask當前實際的標誌值。

我的多個測試(AVD Android 4.2.2,Api 17)顯示,如果一個AsyncTask已經在執行它的doInBackground ,那麼isCancelled() )對任何取消它的嘗試都不會(即繼續為假)作出反應,例如在mViewGroup.removeAllViews(); 或在MainActivityOnDestroy期間,每個都會導致視圖分離

   @Override 
   protected  void  onDetachedFromWindow() { 
    mAsyncTask.cancel(false); // and the same result with mAsyncTask.cancel(true);
    super.onDetachedFromWindow(); 
   } 

如果設法強制停止doInBackground()得益於引入的FlagCancelled ,則onPostExecute()被調用,但onPostExecute() onCancelled()onCancelled(Void result) )都不會被調用(因為API級別為11)。 (我不知道為什麼,因為它們應該被調用, onPostExecute()不應該,“Android API doc說:調用cancel()方法可以保證不會調用onPostExecute(Object)。” - IdleSun回答類似的問題 ) 。

另一方面,如果相同的AsyncTask在取消之前還沒有啟動它的doInBackground() ,那麼一切正常, isCancelled()更改為true,我可以檢查

@Override
    protected void onCancelled() {
        Log.d(TAG, String.format("mAsyncTask - onCancelled: isCancelled = %b, FlagCancelled = %b", this.isCancelled(), FlagCancelled ));
    super.onCancelled();
}



我們的全局AsyncTask類變量

LongOperation LongOperationOdeme = new LongOperation();

和中斷AsyncTask的KEYCODE_BACK動作

   @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            LongOperationOdeme.cancel(true);
        }
        return super.onKeyDown(keyCode, event);
    }

這個對我有用。