Question:
How to decide what Activity a Notification should launch if the target might depend on the configuration (screen size, orientation etc); as is often the case when one uses Fragments?
Details:
Let’s consider the NewsReader sample that demonstrates how to use Fragments to produce an app that plays well with multiple screen sizes and orientations. This app is structured as follows:
- A
HeadlinesFragment. - An
ArticleFragment. - A "main" activity (
NewsReaderActivity). In dual pane mode, this activity contains both the fragments. In single-pane mode, it only contains theHeadlinesFragment. - An
ArticleActivity. This activity is only used in single pane mode; and it contains theArticleFragment.
Now, suppose I were to enhance this app to add a background Service that listens for news updates and notifies the user via status bar notifications whenever there are new news items. A reasonable requirements listing might read like so:
- If there are multiple news updates, clicking on the notification should always take the user to the headlines list.
- If there’s only one update, clicking on the notification should open up the brand new news article.
Note that these requirements translate to different target activities depending on current configuration. In particular,
- Requirement (1) in either mode =
NewsReaderActivity. - Requirement (2) in dual-pane mode =
NewsReaderActivity. - Requirement (2) in single-pane mode =
ArticleActivity.
What would be an elegant way to achieve (2) and (3) above? I think one can safely rule out the possibility of the Service probing for the current configuration to decide what activity to target with the PendingIntent.
One solution I thought of was to skip (2) and always do (3) – i.e., always launch ArticleActivity if there’s only one news update. This snippet from ArticleActivity looked promising:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//...
//...
// If we are in two-pane layout mode, this activity is no longer necessary
if (getResources().getBoolean(R.bool.has_two_panes)) {
finish();
return;
}
//...
//...
}
This code ensures that if one is viewing the ArticleActivity, but switches to a configuration where it is no longer required (for example from portrait to landscape); then the activity simple closes.
However, this won’t work in our case since the intent will have the FLAG_ACTIVITY_NEW_TASK flag set; we would have created a new task, and there is no "previous" activity on the stack. So, calling finish() would just clear the entire stack.
So, how does one decide what activity to launch from a notification, if the activity to launch depends on screen configuration?
This is a really good question!
I’d agree that it would be preferable to keep UI decisions at the UI layer, but having the service make the decision would certainly be an expedient choice. You might use a static method on a UI layer class to keep the decision code technically outside of the service (e.g., a static
createArticlePendingIntent()method onNewsReaderActivitythat the service uses to build itsNotification).Use a
getActivity()PendingIntentforNewsReaderActivityin yourNotification, with enough extras thatNewsReaderActivityknows that it is in this “show the article” scenario. Before it callssetContentView(), have it determine ifArticleActivityis the right answer. If so,NewsReaderActivitycallsstartActivity()to launchArticleActivity, then callsfinish()to get rid of itself (or not, if you want BACK from the article to go toNewsReaderActivity).Or, use a
getActivity()PendingIntentforICanHazArticleActivityin yourNotification.ICanHazArticleActivityhasTheme.NoDisplay, so it will not have a UI. It makes the decision of whether to launchNewsReaderActivityorArticleActivity, callsstartActivity()on the right answer, and then callsfinish(). The advantage over the previous solution is that there is no brief flash ofNewsReaderActivityif the end destination isArticleActivity.Or, use the
createArticlePendingIntent()option I mentioned in the first paragraph of my answer.There may be other options as well, but those are what come to mind.