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();
或在MainActivity
的OnDestroy
期间,每个都会导致视图分离
@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); }
它适用于我。