Я реализовал AsyncTask в своем действия:
performBackgroundTask asyncTask = new performBackgroundTask();
asyncTask.execute();
Теперь, я должен реализовать функциональность кнопки "Cancel", таким образом, я должен остановить выполнение выполняющейся задачи. Я не знаю, как я останавливаю выполняющуюся задачу (фоновая задача).
Поэтому предложите меня, как я отменяю AsyncTask сильно?
Я нашел о Cancel()
метод того же, но я нашел тот вызов cancel(boolean mayInterruptIfRunning)
не обязательно останавливает выполнение фонового процесса. Все, что, кажется, происходит, - то, что AsyncTask выполнит onCancelled () и не выполнит onPostExecute (), когда он завершится.
Просто проверьте isCancelled()
время от времени:
protected Object doInBackground(Object... x) {
while (/* condition */) {
// work...
if (isCancelled()) break;
}
return null;
}
Упомянутый в случае комментариев, который 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 был частным классом одного из представлений, таким образом, методы считывания или методы set флага были необходимы для информирования 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()
не должен, "Android документ API says:Calling отмена () метод гарантирует, что onPostExecute (Объект) никогда не вызывается". - IdleSun
, ответ на подобный вопрос ).
, С другой стороны, если тот же AsyncTask не запустил doInBackground()
перед отменой, то все в порядке, isCancelled()
изменения в истинном и я могу проверить это в [1 127]
@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 методе
Путем создания dismissDialogListerner на 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);
}
, Это работает на меня.
Звоните cancel()
на AsyncTask
. Отменит ли это на самом деле что-нибудь, зависит немного на то, что Вы делаете. Заключить Romain Guy в кавычки:
при вызове отмены (верной) прерывание будет отправлено в фоновый поток, который может помочь прерываемым задачам. Иначе необходимо просто удостовериться, что проверили isCancelled () регулярно в doInBackground () метод. Вы видите примеры этого по code.google.com/p/shelves.
Это действительно зависит от того, что Вы делаете в своем asynctask.
, Если это - цикл, обрабатывающий много файлов, можно просто проверить после того, как каждый регистрирует, если isCanceled () флаг повышен или не, и затем повредитесь от цикла, если это.
, Если это - одна команда строки, которая выполняет очень длинную операцию, нет очень, можно сделать.
лучшее обходное решение не должно было бы использовать метод отмены asynctask и использовать Вашу собственную cancelFlag булевскую переменную. Можно затем протестировать этот cancelFlag в Вашем поствыполняющиеся для решения, что сделать с результатом.