Подтвердить что ты не робот

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

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

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

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

    MyAsyncTask myTask=null;

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

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

Ответ 2

Из 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
}

Ответ 3

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

private class UpdateLibrary extends AsyncTask<Void, Integer, Boolean>{
    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<Void, Integer, Boolean> 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);
    }
}

Ответ 4

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

YourAsyncTask mTask;
Dialog mDialog;

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

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

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

Ответ 5

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

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

public class information extends AsyncTask<String, String, String>
    {
        @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();
        }

    }

Ответ 6

В большинстве случаев, когда я использую AsyncTask, моя бизнес-логика находится в отдельном бизнес-классе, а не в пользовательском интерфейсе. В этом случае у меня не было бы цикла на 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<Void, Void, Boolean> {
    @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;
    }
}

Ответ 7

Вы можете просто запросить отмену, но не прекратить ее. См. Этот ответ.

Ответ 8

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

volatile boolean running;

public void onActivityCreated (Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    running=true;
    ...
    }


public void onDestroy() {
    super.onDestroy();

    running=false;
    ...
}

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

Ответ 9

Как отменить AsyncTask

Полный ответ здесь - пример Android AsyncTask

AsyncTask предоставляет лучшую стратегию отмены, чтобы завершить текущую задачу.

отменить (логическое значение mayInterruptIfitRunning)

myTask.cancel(false) - возвращает isCancelled значение true. Помогает отменить задачу.

myTask.cancel(true) - также делает isCancelled() возвращает true, прерывает фоновый поток и освобождает ресурсы.

Это считается высокомерным способом. Если есть какой-либо метод thread.sleep(), выполняющий в фоновом потоке, cancel (true) прервет фоновый поток в это время. Но отмена (false) будет ждать его и отменить задачу, когда этот метод завершится.

Если вы вызываете cancel() и doInBackground() еще не началось, выполните еще. onCancelled() будет вызывать.

После вызова отмены (…) вы должны периодически проверять значение, возвращаемое isCancelled() в doInbackground(). как показано ниже.

protected Object doInBackground(Params… params)  { 
 while (condition)
{
 ...
if (isCancelled()) 
break;
}
return null; 
}