46

Why do we use the TaskStackBuilder when creating a notification? I do not get the logic behind it.

Can someone please explain.

public void showText(final String text){
    Intent intent = new Intent (this, MainActivity.class);
    TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
    stackBuilder.addParentStack(MainActivity.class);
    stackBuilder.addNextIntent(intent);
    PendingIntent pendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
    Notification notification = new Notification.Builder(this)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle(getString(R.string.app_name))
            .setAutoCancel(true)
            .setPriority(Notification.PRIORITY_MAX)
            .setDefaults(Notification.DEFAULT_VIBRATE)
            .setContentIntent(pendingIntent)
            .setContentText(text)
            .build();
    NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    notificationManager.notify(NOTIFICACTION_ID, notification);
}
Sufian
  • 6,405
  • 16
  • 66
  • 120
MisterNowhere
  • 605
  • 1
  • 6
  • 13

6 Answers6

90

Suppose you have an email sending app and you have two activities in it. One is MainActivity which has the email list and other one is for displaying an email (EmailViewActivity). So now when you receive a new email you display a notification on statusbar. And now you want to view that email when a user clicks on it and also after displaying the email if the user clicks back button you want to show the email list activity(MainActivity). For this scenario we can use TaskStackBuilder. See below example:

public void showEmail(final String text){

        Intent intent = new Intent (this, MainActivity.class);
        TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
        stackBuilder.addParentStack(MainActivity.class);
        stackBuilder.addNextIntent(intent);
        Intent intentEmailView = new Intent (this, EmailViewActivity.class);
        intentEmailView.putExtra("EmailId","you can Pass emailId here");
        stackBuilder.addNextIntent(intentEmailView);
        PendingIntent pendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
        Notification notification = new Notification.Builder(this)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle(getString(R.string.app_name))
                .setAutoCancel(true)
                .setPriority(Notification.PRIORITY_MAX)
                .setDefaults(Notification.DEFAULT_VIBRATE)
                .setContentIntent(pendingIntent)
                .setContentText(text)
                .build();
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(NOTIFICACTION_ID, notification);
    }

Hope you can understand.

Follow below urls for more details: http://developer.android.com/reference/android/support/v4/app/TaskStackBuilder.html http://developer.android.com/guide/components/tasks-and-back-stack.html http://www.programcreek.com/java-api-examples/index.php?api=android.app.TaskStackBuilder

Tharindu Welagedara
  • 2,660
  • 18
  • 27
  • You also don't have to necessarily use StackBuilder only in notifications. You can create a stackbuilder if your app is complicated and just call `pendingIntent.send();` – Pierre Feb 01 '19 at 12:59
  • 2
    also you can use stackBuilder.addNextIntentWithParentStack(targetActivity) to ask android to automatically add all the previous activities that precede the target. For this to work your android manifest should have parentActivityNames properly setup . – Muhammad Ahmed AbuTalib Feb 26 '19 at 15:40
  • Pressing Up should take User to the top of the 'email view' section, i.e. remaining in the app, while pressing back _should_ leave the app, allowing the User to go back to where they came from (an external app). Apps that hijack the back button are doing it wrong (yes, some Google apps do it wrong). – straya Jan 16 '20 at 23:09
  • 2
    PAY ATTENTION !!! Don't use `Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK` with the intent that you pass it to the addNextIntent function. – Amr Jyniat Jun 19 '20 at 12:46
  • don't forget to add `android:parentActivityName=".activity.MainActivity"` – Tushar Monirul Sep 01 '20 at 20:40
  • How do you do this with jetpack compose? – Renz Carlo Aug 17 '22 at 03:42
  • No @TusharMonirul, that is wrong. You don't need to add this flag. `TaskStackBuilder` already handles that by its API. – Michał Dobi Dobrzański Nov 08 '22 at 10:06
32

To provide proper navigation.

1) When the app is launched by App icon (Normal Flow)

enter image description here **

2) When the app is launched by some Notification

enter image description here

General flow of navigation in your app is MainActivity->DetailActivity

But sometimes a Notification might directly open the DetailActivity. In this case, pressing the back button in DetailActivity will not lead you to the `MainActivity. It's an EXPECTED BEHAVIOR. However, you can modify this if you want to navigate back to MainActivity.

How do I do it?

1) Add android:parentActivityName="com.example.myApp.MainActivity in your Activity

This feature was added in Android 4.1. So if you want to target older devices. Add a meta-tag ALSO.

<activity android:name=".Activities.DetailActivity"
    android:parentActivityName=".Activities.MainActivity">
    <meta-data
      android:name="android.support.PARENT_ACTIVITY"
      android:value=".Activities.MainActivity" />
</activity>

2) Use TaskStackBuilder to create a Pending Intent.

public PendingIntent getPendingIntent(Intent intent){

    TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(this);
    taskStackBuilder.addNextIntentWithParentStack(intent);
    PendingIntent pendingIntent = taskStackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);

}

Now pass this Pending intent to create Notifications.

Rohit Singh
  • 16,950
  • 7
  • 90
  • 88
5

We use a TaskStackBuilder to make sure that the back button will play nicely when the activity gets started. The TaskStackBuilder allows you to access the history of activities used by the back button. Basically, we use it when we want the user to navigate to another activity after pressing back button.

Daksh Gargas
  • 3,498
  • 2
  • 23
  • 37
2

I know it has been a while but I came across this problem, this time, my stack had several levels of depth. Looking at the good answers here, I was able to infer it for 3 levels or more of course. As it looks straight forward, it did not look so at the beginning for me because I was triplicating the back stack. Hope it helps someone. Be sure to have the Manifest.xml set up properly

Anyway, for those with several levels, this works nicely:

    Intent level3Intent = new Intent(this, Level3.class);
    level3Intent.putExtra(YOUR STUFF);

    Intent level2Intent = new Intent(this, Level2.class);
    //level2Intent.putExtra(YOUR STUFF);

    Intent level1Intent = new Intent(this, MainActivity.class);

    // Get the PendingIntent containing the entire back stack with the needed extras
    PendingIntent pendingIntent =
            TaskStackBuilder.create(this)
                    .addParentStack(MainActivity.class)
                    .addNextIntent(level1Intent)
                    .addNextIntent(level2Intent)
                    .addNextIntent(level3Intent)
                    .getPendingIntent(requestCode, PendingIntent.FLAG_UPDATE_CURRENT);

return new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID)
            .setContentTitle(notification_title)
            .setContentText(notification_msg)
            .setStyle(new NotificationCompat.BigTextStyle()
             .bigText(notification_msg))
            .setSmallIcon(R.drawable.ic_sea)
            .setDefaults(Notification.DEFAULT_SOUND)
            .setWhen(System.currentTimeMillis())
            .setGroup(OWS_GROUP)
            .setAutoCancel(true)
            .setContentIntent(pendingIntent);
JaviMar
  • 375
  • 5
  • 18
1

The other answers explained it nicely: you use a pending intent to send a user into a detail activity, then you want them to use the back button to go back to the main activity. An alternative way to set this is

Intent detailIntentForToday = new Intent(context, DetailActivity.class);
TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(context);
taskStackBuilder.addNextIntentWithParentStack(detailIntentForToday);
PendingIntent resultPendingIntent = taskStackBuilder
    .getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
resultPendingIntent.send();

For this, you also need to set

android:parentActivityName=".MainActivity"

for the DetailActivity in AndroidManifest.xml.

Pierre
  • 8,397
  • 4
  • 64
  • 80
serv-inc
  • 35,772
  • 9
  • 166
  • 188
0

I had the same problem and I solved in this way:

  1. As already suggested, I added android:parentActivityName=".MainActivity" in my AndroidManifest file.

  2. I also added to every classes the method onResume

  3. I used TaskStackBuilder to create a Pending Intent:

    Intent intent = new Intent(context, myClass); TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(context); taskStackBuilder.addNextIntentWithParentStack(intent); PendingIntent pendingIntent = taskStackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);

TheOldBlackbeard
  • 395
  • 4
  • 22