Android: Отменить задачу Async

Я использую задачу async для загрузки изображения и получения некоторых результатов.

При загрузке изображения я вижу диалог прогресса, написанный в методе onPreExecute () следующим образом:

protected void onPreExecute() { uploadingDialog = new ProgressDialog(MyActivity.this); uploadingDialog.setMessage("uploading"); uploadingDialog.setCancelable(true); uploadingDialog.show(); } 

Хорошо, когда я нажимаю кнопку «Назад», очевидно, что диалог исчезает из-за setCancelable (true).

Но (очевидно) асинхронная задача не останавливается.

Итак, как я могу это исправить? Я хочу отменить диалог и асинхронную задачу, когда я нажимаю кнопку «Назад». Есть идеи?

ИЗМЕНИТЬ: НАЙДИТЕ РЕШЕНИЕ . СМОТРИТЕ МОЙ ОТВЕТ НИЖЕ.

Из SDK:

Отмена задачи

Задача может быть отменена в любое время путем вызова cancel (boolean). Вызов этого метода приведет к последующим вызовам isCancelled (), чтобы вернуть true.

После вызова этого метода onCancelled (Object) вместо onPostExecute (Object) будет вызываться после того, как doInBackground (Object []) вернется.

Чтобы гарантировать, что задача будет отменена как можно быстрее, вы всегда должны проверять возвращаемое значение isCancelled () периодически из doInBackground (Object []), если это возможно (например, внутри цикла).

Таким образом, ваш код подходит для прослушивания диалога:

 uploadingDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { public void onCancel(DialogInterface dialog) { myTask.cancel(true); //finish(); } }); 

Теперь, как я уже упоминал ранее из SDK, вы должны проверить, отменена ли задача или нет, для этого вам нужно проверить isCancelled () внутри метода onPreExecute ().

Например:

 if (isCancelled()) break; else { // do your work here } 

НАЙДЕНО РЕШЕНИЕ : Я добавил слушателя действий перед загрузкойDialog.show () следующим образом:

  uploadingDialog.setOnCancelListener(new DialogInterface.OnCancelListener(){ public void onCancel(DialogInterface dialog) { myTask.cancel(true); //finish(); } }); 

Таким образом, когда я нажимаю кнопку «Назад», вышеуказанный OnCancelListener отменяет диалог и задачу. Также вы можете добавить финиш (), если вы хотите закончить всю операцию по нажатой клавише. Не забудьте объявить задачу async как переменную следующим образом:

  MyAsyncTask myTask=null; 

и выполните свою асинхронную задачу следующим образом:

  myTask = new MyAsyncTask(); myTask.execute(); 

Я потратил некоторое время на то, чтобы понять это, все, что я хотел, было простым примером того, как это сделать, поэтому я подумал, что опубликую, как я это сделал. Это код, который обновляет библиотеку и имеет диалоговое окно прогресса, показывающее, сколько книг было обновлено и отменяется, когда пользователь отклоняет диалог:

 private class UpdateLibrary extends AsyncTask{ private ProgressDialog dialog = new ProgressDialog(Library.this); private int total = Library.instance.appState.getAvailableText().length; private int count = 0; //Used as handler to cancel task if back button is pressed private AsyncTask updateTask = null; @Override protected void onPreExecute(){ updateTask = this; dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); dialog.setOnDismissListener(new OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { updateTask.cancel(true); } }); dialog.setMessage("Updating Library..."); dialog.setMax(total); dialog.show(); } @Override protected Boolean doInBackground(Void... arg0) { for (int i = 0; i < appState.getAvailableText().length;i++){ if(isCancelled()){ break; } //Do your updating stuff here } } @Override protected void onProgressUpdate(Integer... progress){ count += progress[0]; dialog.setProgress(count); } @Override protected void onPostExecute(Boolean finished){ dialog.dismiss(); if (finished) DialogHelper.showMessage(Str.TEXT_UPDATELIBRARY, Str.TEXT_UPDATECOMPLETED, Library.instance); else DialogHelper.showMessage(Str.TEXT_UPDATELIBRARY,Str.TEXT_NOUPDATE , Library.instance); } } 

создайте в своей деятельности некоторые переменные-члены

 YourAsyncTask mTask; Dialog mDialog; 

используйте их для своего диалога и задачи;

в onPause () просто вызовите

 if(mTask!=null) mTask.cancel(); if(mDialog!=null) mDialog.dismiss(); 

Я хотел бы улучшить код. Когда вы запускаете aSyncTask автоматически aSyncTask метод onCancelled() (метод обратного вызова aSyncTask ), и вы можете скрыть свой progressBarDialog .

Вы также можете включить этот код:

 public class information extends AsyncTask { @Override protected void onPreExecute() { super.onPreExecute(); } @Override protected String doInBackground(String... arg0) { return null; } @Override protected void onPostExecute(String result) { super.onPostExecute(result); this.cancel(true); } @Override protected void onProgressUpdate(String... values) { super.onProgressUpdate(values); } @Override protected void onCancelled() { Toast.makeText(getApplicationContext(), "asynctack cancelled.....", Toast.LENGTH_SHORT).show(); dialog.hide(); /*hide the progressbar dialog here...*/ super.onCancelled(); } } 

В большинстве случаев, когда я использую AsyncTask, моя бизнес-логика находится в отдельном бизнес-classе, а не в пользовательском интерфейсе. В этом случае у меня не было бы цикла на doInBackground (). Примером может служить процесс синхронизации, который потребляет службы и сохраняет данные один за другим.

Я в конечном итоге передаю свою задачу бизнес-объекту, чтобы он мог обрабатывать отмену. Моя настройка такова:

 public abstract class MyActivity extends Activity { private Task mTask; private Business mBusiness; public void startTask() { if (mTask != null) { mTask.cancel(true); } mTask = new mTask(); mTask.execute(); } } protected class Task extends AsyncTask { @Override protected void onCancelled() { super.onCancelled(); mTask.cancel(true); // ask if user wants to try again } @Override protected Boolean doInBackground(Void... params) { return mBusiness.synchronize(this); } @Override protected void onPostExecute(Boolean result) { super.onPostExecute(result); mTask = null; if (result) { // done! } else { // ask if user wants to try again } } } public class Business { public boolean synchronize(AsyncTask task) { boolean response = false; response = loadStuff(task); if (response) response = loadMoreStuff(task); return response; } private boolean loadStuff(AsyncTask task) { if (task != null && task.isCancelled()) return false; // load stuff return true; } } 

Вы можете просто попросить об отмене, но на самом деле не прекратите его. См. Этот ответ .

У меня была аналогичная проблема – по сути, я получал NPE в асинхронной задаче после того, как пользователь уничтожил действие. После изучения проблемы с переполнением стека я принял следующее решение:

 volatile boolean running; public void onActivityCreated (Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); running=true; ... } public void onDestroy() { super.onDestroy(); running=false; ... } 

Затем я периодически проверяю «if running» в моем асинхронном коде. Я испытал это, и теперь я не могу «сломать» свою деятельность. Это прекрасно работает и имеет преимущество в том, чтобы быть проще, чем некоторые из решений, которые я видел на SO.

Давайте будем гением компьютера.