Karthik Balakrishnan
Karthik Balakrishnan

Reputation: 4383

Execute onPostExecute on cancelling AsyncTask

As far as I understand once an AsyncTask is called, the result is changed to null and the AsyncTask is cancelled. Is there a way to retain the result and pass it to onPostExecute(String result). developer.android.com says not to call these functions explicitly.

The app basically scans images and if a user cancels the async task, I'd like the async task to display the images scanned so far. So the result should not be set to null.

Is this possible to accomplish? If yes, how?

class openCVOperation extends AsyncTask<String, String, String>{
    private MainActivity context = null;
    /*lots of variables here*/
    public openCVOperation(MainActivity context1) {
        context = context1;// set context from mainActivity
                                        // which
                                        // inherits Activity super class.
                                        // Needed
                                        // for accessing widgets.
    }

    @Override
    protected void onPreExecute() {
        pd = new ProgressDialog(context);
        pd.setIndeterminate(false);
        pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        pd.setMax(100);
        pd.setCancelable(true);
        pd.setCanceledOnTouchOutside(false);
        pd.setMessage("Starting up");
        pd.show();
    }
    @Override
    protected String doInBackground(String... params) {
        publishProgress("Finding path to Storage...");
        path = Environment.getExternalStorageDirectory();
        p = path.getAbsolutePath();
        p=p+"/location";
        rm(p);// this has a loop!
        return null;

    }
    @Override
    protected void onCancelled()
    {
        System.out.println("In onCancelled");
        super.onCancelled();
    }
@Override
    protected void onPostExecute(String result) {
        pd.dismiss();
        /*post execute stuff*
    }

rm(p) has a loop, so I tried using isCancelled() as a condition, but that didn't work.

Upvotes: 0

Views: 2050

Answers (4)

Karthik Balakrishnan
Karthik Balakrishnan

Reputation: 4383

I just had to add this to my doInBackground()

pd.setOnCancelListener(new DialogInterface.OnCancelListener() {

            @Override
            public void onCancel(DialogInterface dialog) {
                // TODO Auto-generated method stub
                task.cancel(true);
            }
        });

Where pd is my progress dialog.

Also make sure you check for isCancelled() in doInBackground() or onCancelled() will never be invoked and the application will force close.

Upvotes: 1

s.d
s.d

Reputation: 29436

Collect the results:

public class MyTask extends AsyncTask<Void,Void,Void>{
  private final List<String> data;

  public MyTask(){
    data =  new ArrayList<String>();
  }

  public synchronized List<String> getData(){
    return new ArrayList<String>(data); //--current data snapshot--
  }

  private synchronized collect(String s){
    data.add(s);
  }     

  @Override
  public Void doInBackground(Void...args){
    //---do stuff--
    collect(/*-stuff-*/);
  }
}

You won't lose anything even if thread is interrupted.

Upvotes: 0

mrres1
mrres1

Reputation: 1155

If onCancelled is not being called, then your rm method is still running. Because as you mentioned, it's running a loop.

The best way to control the process (know if it needs to be stopped) is by polling or tediously checking the status of a volatile boolean variable within your rm method.

For example, create a static volatile boolean variable within your AsyncTask class called cancel. Set this variable to false in the onPreExecute method.

In your rm method, check to see if cancel is true before and after the heavy tasks (opening a file, reading a file, part of a download loop).

If it's true, then break out of the method with a return statement. Better yet, make your rm method return an Integer, 0 for Good and 1 for cancelled.

And finally, right before the doInBackground method hits return, see if you need to call a cancel on the thread or not.

public class asyncTask extends AsyncTask<Void, Void, Void>
{
    private static synchronized boolean cancel;

    protected void onPreExecute()
    {
        cancel = false;
    }

    protected String doInBackground(Void ... params)
    {

        rm(p);

        if(cancel)
            asyncTask.cancel;
        else
            return null;
    }

    protected void onCancelled()
    {
        // only executed if doInBackground resulted in a cancel == true
    }

    protected void onPostExecute(Void param)
    {
        /// only executed if doInBackground resulted in a cancel == false 
    }

    private int rm(String str)
    {
        if(cancel)
            return 1;

        //do part of task

        if(cancel)
            return 1;

        //another part of task

        if(cancel)
            return 1;

        //another part of task

        return cancel ? 1 : 0;
    }

}

Upvotes: -1

Hoan Nguyen
Hoan Nguyen

Reputation: 18151

In the doInBackground

if (isCancelled())
{
    return // image so far
}


onPostExecute(String result)
{

     // show result
}

Upvotes: 1

Related Questions