Android – 强制取消AsyncTask

我在我的一个活动中实现了AsyncTask:

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

现在,我需要实现“取消”buttonfunction,所以我必须停止正在运行的任务的执行。 我不知道如何停止正在运行的任务(后台任务)。

所以请build议我,我如何强制取消AsyncTask?

更新:

我发现有关的Cancel()方法相同,但我发现调用cancel(boolean mayInterruptIfRunning)不一定会停止执行后台进程。 所有似乎发生的事情是,AsyncTask将执行onCancelled(),并且在完成时不会运行onPostExecute()。

稍后检查isCancelled()

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

调用AsyncTask上的cancel() 。 这是否会取消任何事情取决于你在做什么。 引用Romain Guy:

如果你调用cancel(true),一个中断将被发送到后台线程,这可能有助于中断任务。 否则,您应该确保在doInBackground()方法中定期检查isCancelled()。 你可以在code.google.com/p/shelves上看到这方面的例子。

这真的取决于你在asynctask中做什么。

如果它是一个处理大量文件的循环,那么你可以在每个文件之后检查isCanceled()标志是否被引发,如果是则从循环中断开。

如果这是一个执行很长操作的单行命令,那么你可以做的事情不多。

最好的解决方法是不使用asynctask的cancel方法,并使用自己的cancelFlag布尔值。 然后,您可以在postExecute中testing这个cancelFlag来决定如何处理结果。

在评论情况下提到的isCancelled() always returns false even i call asynctask.cancel(true); 如果closures我的应用程序是特别有害的,但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当前的实际标志值。

我的多个testing(AVD Android 4.2.2,Api 17)已经表明,如果一个AsyncTask已经在执行它的doInBackground ,那么isCancelled() )对任何取消它的尝试都不会(即继续为false)作出反应,例如在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文档说:调用cancel()方法保证onPostExecute(对象)从不调用。” – 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显示的通常的进度对话框是当用户按下后退button时在AsyncTask上取消的第一件事情。 2. AsyncTask可能在doInBackground方法中

通过在ProgressDialog上创builddismissDialogListerner,用户可以按下后退button,实际上使AsycnTask无效并closures对话框本身。

这里是一个例子:

 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类variables

 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); } 

它适用于我。