Android:取消异步任务

问题描述 投票:55回答:9

我使用异步任务上传图像并获得一些结果。

在上传图像时,我看到一个进度对话框,用onPreExecute()方法编写,如下所示:

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

好的,当我按下后退按钮时,显然对话框因setCancelable(true)而消失。

但(显然)异步任务不会停止。

那么我该如何解决这个问题呢?当我按下后退按钮时,我想取消对话和异步任务。有任何想法吗?

编辑:找到解决方案。请看下面我的答案。

android asynchronous task back
9个回答
100
投票

来自SDK:

取消任务

可以通过调用cancel(boolean)随时取消任务。调用此方法将导致后续调用isCancelled()返回true。 调用此方法后,将在doInBackground(Object [])返回后调用onCancelled(Object)而不是onPostExecute(Object)。 为确保尽快取消任务,应始终定期从doInBackground(Object [])检查isCancelled()的返回值,如果可能的话(例如在循环内)。

所以你的代码适合对话框监听器:

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

现在,正如我之前在SDK中提到的那样,您必须检查任务是否被取消,因为您必须在onPreExecute()方法中检查isCancelled()。

例如:

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

32
投票

发现解决方案:我在上传Digial.show()之前添加了一个动作监听器:

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

这样,当我按下后退按钮时,上面的OnCancelListener取消了对话框和任务。如果要在后退时完成整个活动,也可以添加finish()。请记住将异步任务声明为如下变量:

    MyAsyncTask myTask=null;

并像这样执行你的异步任务:

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

10
投票

我花了一段时间搞清楚这一点,我想要的只是一个如何做到的简单例子,所以我想我会发布我是如何做到的。这是一些更新库的代码,并有一个进度对话框,显示已更新的书籍数量,并在用户解除对话框时取消:

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

9
投票

在你的活动中创建一些成员变量

YourAsyncTask mTask;
Dialog mDialog;

将这些用于对话和任务;

在onPause()中只需调用

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

5
投票

我想改进代码。当你取消qazxsw poi时,qazxsw poi(qazxsw poi的回调方法)会被自动调用,你可以隐藏你的aSyncTask

您也可以包含此代码:

onCancelled()

3
投票

大多数时候我使用AsyncTask我的业务逻辑是在一个独立的业务类而不是在UI上。在那种情况下,我在doInBackground()中没有循环。一个示例是同步过程,它消耗服务并一个接一个地保存数据。

我最终将我的任务交给业务对象,以便它可以处理取消。我的设置是这样的:

aSyncTask

2
投票

你可以要求取消但不能真正终止它。看到这个progressBarDialog


2
投票

我有一个类似的问题 - 基本上我是在用户销毁活动后在异步任务中获得NPE。在研究Stack Overflow上的问题后,我采用了以下解决方案:

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

    }

然后,我在异步代码中定期检查“是否正在运行”。我有压力测试这个,我现在无法“打破”我的活动。这非常有效,并且比我在SO上看到的一些解决方案更简单。


2
投票

如何取消AsyncTask

完整的答案在这里 - 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; } }

AsyncTask提供了更好的取消策略,以终止当前正在运行的任务。

取消(布尔值mayInterruptIfitRunning)

myTask.cancel(false) - 它使得isCancelled返回true。有助于取消任务。

myTask.cancel(true) - 它还使isCancelled()返回true,中断后台线程并释放资源。

它被认为是一种傲慢的方式,如果在后台线程中执行任何thread.sleep()方法,则cancel(true)将在那时中断后台线程。但是,当该方法完成时,cancel(false)将等待它并取消任务。

如果调用cancel()并且doInBackground()尚未开始执行。 onCancelled()将调用。

在调用cancel(...)之后,你应该定期检查doCbacklled()在doInbackground()上返回的值。如下图所示。

answer
© www.soinside.com 2019 - 2024. All rights reserved.