views:

756

answers:

3

I am running remote audio-file-fetching and audio file playback operations in a background thread using AsyncTask. A Cancellable progress bar is shown for the time the fetch operation runs.

I want to cancel/abort the AsyncTask run when the user cancels (decides against) the operation. What is the ideal way to handle such a case?

+1  A: 

Simple: don't use an AsyncTask. AsyncTask is designed for short operations that end quickly (tens of seconds) and therefore do not need to be canceled. "Audio file playback" does not qualify. You don't even need a background thread for ordinary audio file playback.

CommonsWare
are you suggesting we use regular java thread and "abort" the thread run using volatile boolean variable - the conventional Java way?
Samuh
I don't know about `volatile` -- I tend to use `java.util.concurrent` objects for that sort of thing.
CommonsWare
No offense Mike, but that's not an acceptable answer. AsyncTask has a cancel method, and it should work. As far as I can tell, it doesn't - but even if I'm doing it wrong, then there should be a right way to cancel a task. The method wouldn't exist otherwise.And even short tasks may need canceling - I have an Activity where it begins an AsyncTask immediately upon loading, and if the user hits back immediately after opening the task, they'll see a Force Close a second later when the task finishes but no context exists for it to use in its onPostExecute.
Klondike
@Klondike: I have no idea who "Mike" is. "but that's not an acceptable answer" -- you are welcome to your opinion. "AsyncTask has a cancel method, and it should work." -- canceling threads in Java has been a problem for ~15 years. It has nothing much to do with Android. With respect to your "Force Close" scenario, that can be solved by a boolean variable, which you test in `onPostExecute()` to see whether you should go ahead with the work.
CommonsWare
Yikes, can't believe I said "Mike" - my apologies on that.Canceling threads in Java may have been a problem for 15 years, but if it's not reliable there shouldn't be a method in the Android SDK that has a boolean flag that implies the thread will be actively interrupted if it's that non-deterministic. It may as well not be there.
Klondike
+1  A: 

Just discovered that AlertDialogs's boolean cancel(...); I've been using everywhere actually does nothing. Great.
So...

public class MyTask extends AsyncTask<Void, Void, Void> {

    private volatile boolean running = true;
    private final ProgressDialog progressDialog;

    public MyTask(Context ctx) {
        progressDialog = gimmeOne(ctx);

        progressDialog.setCancelable(true);
        progressDialog.setOnCancelListener(new OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                // actually could set running = false; right here, but I'll
                // stick to contract.
                cancel(true);
            }
        });

    }

    @Override
    protected void onPreExecute() {
        progressDialog.show();
    }

    @Override
    protected void onCancelled() {
        running = false;
    }

    @Override
    protected Void doInBackground(Void... params) {

        while (running) {
            // does the hard work
        }
        return null;
    }

    // ...

}
alex
additionally I called the cancel method on the AsyncTask
Samuh
+1  A: 

The only way to do it is by checking the value of the isCancelled() method and stopping playback when it returns true.

dbyrne