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

1

6

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!

Amplifier answered 12/6, 2012 at 17:27 Comment(0)
J
1

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;
Jase answered 12/6, 2012 at 18:55 Comment(3)
That's the issue I'm having is actually passing reference of the AsyncTask to the activity above. I tried to implement Serializable on the AsyncTask and use putExtra() on the Intent I set up as the PendingIntent, but I got an exception saying that the object is not serializable. Is there another way to pass a reference to the AsyncTask to my activity?Amplifier
Ok I think that the way I'm doing it just won't work. The notification task I posted was ONLY for use as the PendingIntent when the status bar notification was clicked. The AsyncTask was actually in the class that handled the screen where you can click to download the file. Sounds like I need to move my AsyncTask to the DownloadNotificationActivity and execute it in the onCreate of that class. Then handle the onClick event for the notification. I'll let you know what happens.Amplifier
Trying what I said in my previous comment did not work. I thank you for your assistance @Motes. I've updated the topic with more info (at the bottom). I feel like I'm going about this the wrong way. I need to look for other options. I thought about trying a Broadcast and BraodcastReceiver but I'm not sure how well putting a receiver on an AsyncTask will work.Amplifier

© 2022 - 2024 — McMap. All rights reserved.