Android:取消异步任务

时间:2011-05-18 02:13:27

标签: android asynchronous task back

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

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

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

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

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

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

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

9 个答案:

答案 0 :(得分:100)

来自SDK:

  

取消任务

     

可以通过调用cancel(boolean)随时取消任务。   调用此方法将导致后续调用isCancelled()   返回真实。

  调用此方法后,onCancelled(Object),而不是   doInBackground(Object [])返回后将调用onPostExecute(Object)。

  确保尽快取消任务,   你应该定期检查isCancelled()的返回值   doInBackground(Object []),如果可能的话(例如在循环内)。

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

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
}

答案 1 :(得分: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();

答案 2 :(得分: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);
    }
}

答案 3 :(得分:9)

在您的活动中创建一些成员变量,如

YourAsyncTask mTask;
Dialog mDialog;

将这些用于对话和任务;

onPause()中的

只需调用

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

答案 4 :(得分: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();
        }

    }

答案 5 :(得分:3)

我使用AsyncTask的大部分时间我的业务逻辑都是在一个独立的业务类上,而不是在UI上。在那种情况下,我在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;
    }
}

答案 6 :(得分:2)

你可以要求取消,但不能真正终止它。请参阅此answer

答案 7 :(得分:2)

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

volatile boolean running;

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

    running=true;
    ...
    }


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

    running=false;
    ...
}

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

答案 8 :(得分:1)

如何取消AsyncTask

完整答案在这里-Android AsyncTask Example

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

取消(布尔值mayInterruptIfitRunning)

myTask.cancel(false)-使isCancelled返回true。帮助取消任务。

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

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

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

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

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