Android – Отмена AsyncTask

Я реализовал AsyncTask в своей деятельности:

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

Теперь мне нужно реализовать функциональность кнопки «Отмена», поэтому мне нужно остановить выполнение выполняемой задачи. Я не знаю, как остановить выполняемую задачу (фоновая задача).

Итак, пожалуйста, предложите мне, как я могу отменить AsyncTask?

Обновить:

Я нашел об методе Cancel() того же самого, но я обнаружил, что вызов cancel(boolean mayInterruptIfRunning) не обязательно останавливает выполнение фонового процесса. Все, что кажется, это то, что AsyncTask будет выполнять onCancelled () и не будет запускаться onPostExecute (), когда он будет завершен.

Solutions Collecting From Web of "Android – Отмена AsyncTask"

Просто проверьте isCancelled() раз в то время:

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

AsyncTask вызов cancel() в AsyncTask . Независимо от того, действительно ли это отменит что-либо, зависит немного от того, что вы делаете. Процитировать Romain Guy:

Если вы вызываете cancel (true), прерывание будет отправлено в фоновый поток, что может помочь прерывистым задачам. В противном случае вы должны просто регулярно проверять isCancelled () в своем методе doInBackground (). Вы можете увидеть примеры этого на code.google.com/p/shelves.

Это действительно зависит от того, что вы делаете в своей асинтете.

Если это цикл, обрабатывающий много файлов, вы можете просто проверить после каждого файла, если флаг isCanceled () поднят или нет, а затем перерыв из вашего цикла, если он есть.

Если это однострочная команда, которая выполняет очень длительную операцию, вы не можете многое сделать.

Лучшим обходным решением было бы не использовать метод отмены asynctask и использовать ваш собственный cancelFlag boolean. Затем вы можете протестировать этот cancelFlag в postExecute, чтобы решить, что делать с результатом.

Упомянутый в комментарии случай, который isCancelled() always returns false even i call asynctask.cancel(true); Особенно вредно, если я закрываю приложение, но AsyncTask продолжает работать.

Чтобы решить эту проблему, я изменил предложенный Jacob Nordfalk код 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(); Или во время OnDestroy MainActivity , каждый из которых приводит к отключению просмотров

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

Если мне удастся принудительно остановить doInBackground() благодаря введенному FlagCancelled , onPostExecute() , но ни onCancelled() ни onCancelled(Void result) (с уровня API 11) не вызывается. (Я понятия не имею, почему, потому что они должны быть вызваны, а onPostExecute() не должен », – говорится в документе API Android API. Вызов метода 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 не следует использовать для длительных операций, иногда его можно поймать в задаче, которая не отвечает (например, неответственный HTTP-вызов). В этом случае может потребоваться отменить AsyncTask.

У нас есть проблемы в этом. 1. Обычный диалог выполнения, отображаемый с помощью AsyncTask, является первым, что отменено на AsyncTask, когда пользователь нажал кнопку «Назад». 2. AsyncTask может быть в методе doInBackground

Создав функцию offsetDialogListerner на ProgressDialog, пользователь может нажать кнопку «Назад» и фактически аннулировать AsycnTask и закрыть сам диалог.

Вот пример:

 public void openMainLobbyDoor(String username, String password){ if(mOpenDoorAsyncTask == null){ mOpenDoorAsyncTask = (OpenMainDoor) new OpenMainDoor(username, password, Posts.API_URL, mContext, "Please wait while I unlock the front door for you!").execute(null, null, null); } } private class OpenMainDoor extends AsyncTask<Void, Void, Void>{ //declare needed variables String username, password, url, loadingMessage; int userValidated; boolean canConfigure; Context context; ProgressDialog progressDialog; public OpenMainDoor(String username, String password, String url, Context context, String loadingMessage){ userValidated = 0; this.username = username; this.password = password; this.url = url; this.context = context; this.loadingMessage = loadingMessage; } /** * used to cancel dialog on configuration changes * @param canConfigure */ public void canConfigureDialog(boolean canConfigure){ this.canConfigure = canConfigure; } @Override protected void onPreExecute(){ progressDialog = new ProgressDialog(this.context); progressDialog.setMessage(loadingMessage); progressDialog.setIndeterminate(true); progressDialog.setCancelable(true); progressDialog.setOnCancelListener(new OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { mOpenDoorAsyncTask.cancel(true); } }); progressDialog.show(); this.canConfigure = true; } @Override protected Void doInBackground(Void... params) { userValidated = Posts.authenticateNTLMUserLogin(username, password, url, context); while(userValidated == 0){ if(isCancelled()){ break; } } return null; } @Override protected void onPostExecute(Void unused){ //determine if this is still attached to window if(canConfigure) progressDialog.dismiss(); if(userValidated == 1){ saveLoginValues(username, password, true); Toast.makeText(context, R.string.main_login_pass, Toast.LENGTH_SHORT).show(); }else{ saveLoginValues(username, password, false); Toast.makeText(context, R.string.main_login_fail, Toast.LENGTH_SHORT).show(); } nullifyAsyncTask(); } @Override protected void onCancelled(){ Toast.makeText(context, "Open door request cancelled!", Toast.LENGTH_SHORT).show(); nullifyAsyncTask(); } } 

Наша глобальная переменная класса AsyncTask

 LongOperation LongOperationOdeme = new LongOperation(); 

И действие KEYCODE_BACK, которое прерывает AsyncTask

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

Меня устраивает.