Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: How do I access an AsyncTask from a PendingIntent created by a status bar notification?

My application starts an AsyncTask which downloads a file from a URL. At the same time it creates a status bar Notification which tells the user the percentage complete of the download.

I'm trying to make my application respond to clicking the notification. If the download is still in progress, I want to show a DialogInterface which asks them if they want to stop the download. Clicking yes should stop the download.

The problem I'm having is I'm not sure how to access my Async task from the PendingIntent that I set up for the notification. I can get the DialogInterface to show easy enough, but I'm not sure how to show the Activity that's going off where the download is to stop it.

I tried making a Helper class that had access to the notification as well as the File object referring to the downloadable file, but I get an error saying that the object is not serializable (it does implement Serializable). The helper class also included a member that would hold the progress of the download which is what I would use for the condition on whether to show the dialog or not.

I was thinking of using a Brodcast Action and receiver, but I'm not sure where to put the receiver. Would it go in the class that extends the AsyncTask?

Any help would be appreciated. This is the PendingIntent attached to the Notification. If you would like to see more code, just ask.

public class DownloadNotificationActivity extends Activity {

/** Called when the activity is first created. */
@Override
public void onCreate( Bundle savedInstanceState ) {
    super.onCreate( savedInstanceState );

    Intent i = getIntent();

    DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {

        @Override
        public void onClick( DialogInterface dialog, int which ) {
            switch ( which ) {
                case DialogInterface.BUTTON_POSITIVE :
                    // Yes button clicked
                    // Stop download
                    finish();
                    break;

                case DialogInterface.BUTTON_NEGATIVE :
                    // No button clicked
                    finish();
                    break;
            }
        }
    };

    if ( /* download not complete */ ) {
        AlertDialog.Builder builder = new AlertDialog.Builder( this );
        builder.setMessage( R.string.stop_download ).
                setPositiveButton( R.string.yes, dialogClickListener ).
                setNegativeButton( R.string.no, dialogClickListener ).show();
    }
    else {
        // Access file
    }

}
}

So to be clear, I have a ViewDetailActivity class. It has an inner class called DownloadFile which extends AsyncTask and is executed when the user clicks a button on the screen. In the doInBackground() method of DownloadFile, a download of an mp3 is started from a URL and a status bar Notification is created and updated based on the amount of the file that is downloaded. The PendingIntent of the Notification is created with the DownloadNotificationActivity (code shown) and it should show a dialog which, of "Yes" is selected, should cancel the download in the AsyncTask.

My issue is that I need to get word back to the DownloadFile task that the download has been canceled and I'm not sure how to access the DownloadFile from the DownloadNotificationActivity in order to cancel it.

Thanks in advance!

like image 216
Shino Avatar asked Jun 12 '12 17:06

Shino


1 Answers

In your asynctask, you need to check for isCancelled() in the doInBackground() and abort when cancelled. From your notification, you call cancel() on the asynctask.

To do this you need to pass reference to the AsyncTask to your notification activity.

For example:

You create the AsyncTask like this:

class MyAsyncTask extends AsyncTask<Void, Integer, Void> {
        @Override
        protected Void doInBackground(Void... unused) { //be sure to check isCancelled here, i.e. if (isCancelled()) break;

Then in your main Activity you create the AsyncTask like:

public class MyActivity extends Activity {
    private MyAsyncTask zeTask;
    @Override
    public void onCreate(Bundle savedInstanceState) {
              zeTask= new MyAsyncTask();
              zeTask.execute();

Then, when you create the notification and want to cancel the async task just refer to it as zeTask. The MyAsyncTask needs to be in the same activity as the notification and zeTask can be a variable that holds the reference to your AsyncTask.

switch ( which ) {
                case DialogInterface.BUTTON_POSITIVE :
                    zeTask.cancel();
                    finish();
                    break;
like image 197
Motes Avatar answered Oct 08 '22 03:10

Motes