Android: How to attach an extra to an Intent/PendingIntent in a Notification (solution)

I’m working on a very small Android “notifications” app where I a) display a notification using a background service, b) the user taps the notification, which c) takes them to a view that shows the full text of the notification. To get this to work, I need to send the full text along with the notification. However, this didn’t work easily. The text that was shown by my full view would be updated once, then never again.

After a lot of googling and trial and error, I finally got this approach in my sendNotification method working:

public void sendNotification() {
    String randomQuote = getRandomQuote();

    Intent showFullQuoteIntent = new Intent(this, ShowFullQuoteActivity.class);
    showFullQuoteIntent.putExtra(INTENT_KEY, randomQuote);

    // both of these approaches now work: FLAG_CANCEL, FLAG_UPDATE; the uniqueInt may be the real solution.
    //PendingIntent pendingIntent = PendingIntent.getActivity(this, uniqueInt, showFullQuoteIntent, PendingIntent.FLAG_CANCEL_CURRENT);
    int uniqueInt = (int) (System.currentTimeMillis() & 0xfffffff);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, uniqueInt, showFullQuoteIntent, PendingIntent.FLAG_UPDATE_CURRENT);

    Notification notification = new NotificationCompat.Builder(this)
            .setTicker(randomQuote)
            .setSmallIcon(android.R.drawable.ic_menu_view)
            .setContentTitle(randomQuote)
            .setContentText(randomQuote)
            .setContentIntent(pendingIntent)
            .setAutoCancel(true)
            .build();

    NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    notificationManager.notify(0, notification);
}

Honestly, at the moment I don’t know why these approaches are working. As noted in the comments, this code works properly when I use any of the flags shown on the PendingIntent.getActivity method call. One thing I can say for sure: that method call is where the problem was.

The Android PendingIntent.getActivity method (API)

FWIW, yes, I have read the PendingIntent API documentation. As you can see from this image, the requestCode could probably be documented better (IMHO):

Complete source code

If it helps to see the full source code for my IntentService, here it is, all comments included:

package com.alvinalexander.motify;

import java.util.Random;
import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

public class PollingService extends IntentService {

    private static final String TAG = "PollingService";
    private static final Random random = new Random();
    public static final String INTENT_KEY = "THE_QUOTE";
    public static final String INTENT_KEY_2 = "INTENT_KEY_2";

    public PollingService() {
        super(TAG);
    }

    @Override
    public void onHandleIntent(Intent intent) {
        Log.i(TAG, "ENTERED onHandleIntent");
        sendNotification();
    }

    public void sendNotification() {
        Log.i(TAG, "ENTERED sendNotification");

        String randomQuote = getRandomQuote();
        Log.i(TAG, "QUOTE: " + randomQuote);

        Intent showFullQuoteIntent = new Intent(this, ShowFullQuoteActivity.class);
        showFullQuoteIntent.putExtra(INTENT_KEY, randomQuote);

        // from stackoverflow.com/questions/11551195/intent-from-notification-does-not-have-extras
        //showFullQuoteIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);

        // stackoverflow.com/questions/7370324/notification-passes-old-intent-extras/9330144
        // @see http://developer.android.com/reference/android/app/PendingIntent.html#FLAG_UPDATE_CURRENT

        // both of these approaches now work: FLAG_CANCEL, FLAG_UPDATE; the uniqueInt may be the real solution.
        //PendingIntent pendingIntent = PendingIntent.getActivity(this, uniqueInt, showFullQuoteIntent, PendingIntent.FLAG_CANCEL_CURRENT);
        int uniqueInt = (int) (System.currentTimeMillis() & 0xfffffff);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, uniqueInt, showFullQuoteIntent, PendingIntent.FLAG_UPDATE_CURRENT);

        Notification notification = new NotificationCompat.Builder(this)
                .setTicker(randomQuote)
                .setSmallIcon(android.R.drawable.ic_menu_view)
                .setContentTitle(randomQuote)
                .setContentText(randomQuote)
                .setContentIntent(pendingIntent)
                .setAutoCancel(true)
                .build();

        NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        notificationManager.notify(0, notification);
    }

    private String getRandomQuote() {
        Resources res = getResources();
        String[] quotes = res.getStringArray(R.array.motivational_quotes);
        int randomIndex = random.nextInt(quotes.length);
        String randomQuote = quotes[randomIndex];
        return randomQuote;
    }

}

The receiving Activity/Fragment

I’ll update this article when I learn for sure why the current code is working, but as mentioned, my “extras” string is now properly being passed through the Intent and PendingIntent, and I’m able to retrieve the intent extra in my fragment on the receiving end like this:

public static class ShowFullQuoteFragment extends Fragment {

    private static final String PF_TAG = "ShowFullQuoteFragment";

    @Override
    public View onCreateView(LayoutInflater inflater,
                             ViewGroup container,
                             Bundle savedInstanceState) {
        Log.i(PF_TAG, "ENTERED onCreateView");

        // get the 'extra' from the intent
        String quote = (String)getActivity().getIntent().getStringExtra(PollingService.INTENT_KEY);
        Log.i(PF_TAG, "QUOTE: " + quote);

        View rootView = inflater.inflate(R.layout.fragment_show_full_quote, container, false);
        TextView quoteLabel = (TextView)rootView.findViewById(R.id.put_quote_here);
        quoteLabel.setText(quote);
        return rootView;
    }
}