In the last lesson, we already looked at how to display Activity after clicking on a message. But there was a simple case. In this lesson, let’s look at more interesting cases.
To understand everything that goes on, you will need knowledge of Activity Tasks Stack. You can read about this in the documentation or in Lesson 116.
For example, let’s take a mail application consisting of three screens: a list of letters (MainActivity), the contents of a letter (DetailsActivity) and information about the new version (WhatsNewActivity). When you start MainActivity, it displays the letters, and when you click on the letter, DetailsActivity opens with the contents of the letter.
The application has some service that is connected to the server. When a new letter appears on the server, the service downloads it and shows the message to the user. The user clicks on it and opens DetailsActivity to view the email.
Similarly, the service receives information about a new version of the application and creates messages for the event. Clicking on the message will open WhatsNewActivity, which will detail the new features of the application.
But there are different ways to open two of these Activities.
We will open DetailsActivity in the same way as if it had been opened from MainActivity. That is, we will open two Activities (one after the other): MainActivity and DetailsActivity. By clicking Back in the started DetailsActivity, the user will be taken to MainActivity.
The WhatsNewActivity screen is different. It is only intended to be opened from the message. You can’t open it from the app. That is, there is simply no such list or button in the app that would open WhatsNewActivity. Because it is not particularly important information, and if you suddenly wanted to see it, you can go to the site of the program.
Let’s look at how these two options are implemented
DetailsActivity as part of the program
Let’s first configure DetailsActivity in the manifest:
The parentActivityName attribute and the meta-data tag do exactly the same thing here – they report that DetailsActivity opens with MainActivity. That is, MainActivity is the parent of DetailsActivity. The only difference is that meta-data works for Android 4.0.3 and below and parentActivityName for Android 4.1 and above. That is, we specify the parentActivity parameter in two different ways to ensure compatibility. If your application no longer supports Android below 4.1, you may not specify meta-data.
Next we create a message. All the same as we covered in the previous lesson. Only the PendingIntent creation will be different.
// Create PendingIntent Intent resultIntent = new Intent(this, DetailsActivity.class); resultIntent.putExtra(EXTRA_ITEM_ID, itemId); TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); stackBuilder.addParentStack(DetailsActivity.class); stackBuilder.addNextIntent(resultIntent); PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
EXTRA_ITEM_ID is your string constant
Consider the steps that are happening here.
Let’s create a regular Intent to open DetailsActivity. We pass the id there so Activity knows what information it needs to display. Everything is clear and usual here.
We then create a TaskStackBuilder, a tool that will help us generate a sequence of Activity calls. We need to first start the Parent Activity for DetailsActivity (ie MainActivity) and then DetailsActivity.
We call the addParentStack method and specify DetailsActivity in it, that is, we ask in the call stack to add Activity, which is the parent for DetailsActivity. The TaskStackBuilder goes to the manifest and sees that MainActivity is spelled as DetailsActivity as the parent (parentActivityName). TaskStackBuilder adds MainActivity to the call stack.
At addNextIntent, we just pass Intent to run DetailsActivity. TaskStackBuilder will add it to your call stack.
As a result, TaskStackBuilder contains two Activities in the call stack: first MainActivity and then DetailsActivity.
With the getPendingIntent method, it forms a PendingIntent that we can pass to the message builder. And after clicking on the message, the Activities that were in the call stack generated in TaskStackBuilder will be opened.
Run, click on the message
And two Activity opens. Clicking Back in DetailsActivity we get to MainActivity.
Everything works, but one little thing remains. The message does not close after clicking on it. You can use setAutoCancel, as we did in the last lesson, but this is not quite right in this case.
Let’s say you get a message about a new email. But you did not open the expiry message, but decided to go to the application immediately, they already saw a new letter, opened it, read it and closed the application. The letter is now read by you and the message is still hanging, although it is no longer relevant.
It will be more correct to delete the message when opening the corresponding message. Consider how this can be implemented.
Message creation code:
long itemId = 12345678910L; int notificationId = ((Long)itemId).intValue(); // Create PendingIntent Intent resultIntent = new Intent(this, DetailsActivity.class); resultIntent.putExtra(EXTRA_ITEM_ID, itemId); TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); stackBuilder.addParentStack(DetailsActivity.class); stackBuilder.addNextIntent(resultIntent); PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); // Create Notification NotificationCompat.Builder builder = new NotificationCompat.Builder(this) .setSmallIcon(R.mipmap.ic_launcher) .setContentTitle("Title") .setContentText("Notification text") .setContentIntent(resultPendingIntent); Notification notification = builder.build(); // Show Notification NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); notificationManager.notify(notificationId, notification);
The whole code is already familiar to us. I will go through only part id.
You have id letters (itemId), let it be long. Using itemId, you can create an id for the notification (notificationId) and then specify it in the notify method.
Now, to delete a message, you need to use the same notificationId in the cancel method.
We implement this in DetailsActivity:
long itemId = getIntent().getLongExtra(EXTRA_ITEM_ID, 0); int notificationId = ((Long)itemId).intValue(); NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); notificationManager.cancel(notificationId);
We get itemId from Intent. With itemId we again form the notificationId and use it in the cancel method.
As a result, when you open a letter in DetailsActivity, the message corresponding to that letter will be deleted. And no matter, you came to this screen by yourself or by tapping on a message.
It is important that the notificationId used in and deleting the message coincide. In our example, we compute it with itemId simply by taking int part from long. You may have another way of obtaining or generating this id.
WhatsNewActivity, separate from the application
Consider another option. I would remind that it involves opening the Activity separately from the program.
To do this, Activity must be set up as follows in the manifest:
launchMode is set to singleTask for Activity to search or create its own task. we make taskAffinity empty so that Activity does not disappear into the main application tray. excludeFromRecents is required so that the activity’s activity does not appear in the recent list of applications.
Message creation is done according to the usual scheme, only Intent needs to add a couple of flags for Activity to start in a new empty TASK
Intent resultIntent = new Intent(this, WhatsNewActivity.class); resultIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
As a result, clicking on the message will open Activity in a separate from your application TASK.
And it will not be visible in the list of recently launched applications