This lesson teaches you to:
- Synthesize a new Back Stack for Deep Links
- Implement Back Navigation for Fragments
- Implement Back Navigation for WebViews
You should also read
Back navigation is how users move backward through the history of screens they previously visited. All Android devices provide a Back button for this type of navigation, so your app should not add a Back button to the UI.
In almost all situations, the system maintains a back stack of activities while the user navigates your application. This allows the system to properly navigate backward when the user presses the Back button. However, there are a few cases in which your app should manually specify the Back behavior in order to provide the best user experience.
Back Navigation Design
Before continuing with this document, you should understand the concepts and principles for Back navigation as described in the Navigation design guide.
Navigation patterns that require you to manually specify the Back behavior include:
- When the user enters a deep-level activity directly from a notification, an app widget, or the navigation drawer.
- Certain cases in which the user navigates between fragments.
- When the user navigates web pages in a
WebView
.
How to implement proper Back navigation in these situations is described in the following sections.
Synthesize a new Back Stack for Deep Links
Ordinarily, the system incrementally builds the back stack as the user navigates from one activity to the next. However, when the user enters your app with a deep link that starts the activity in its own task, it's necessary for you to synthesize a new back stack because the activity is running in a new task without any back stack at all.
For example, when a notification takes the user to an activity deep in your app hierarchy, you should add activities into your task's back stack so that pressing Back navigates up the app hierarchy instead of exiting the app. This pattern is described further in the Navigation design guide.
Specify parent activities in the manifest
Beginning in Android 4.1 (API level 16), you can declare the logical parent of each
activity by specifying the android:parentActivityName
attribute
in the <activity>
element. This allows the system to facilitate navigation patterns
because it can determine the logical Back or Up navigation path with this
information.
If your app supports Android 4.0 and lower, include the
Support Library with your app and
add a <meta-data>
element inside the <activity>
. Then specify the parent activity as the value
for android.support.PARENT_ACTIVITY
, matching the android:parentActivityName
attribute.
For example:
<application ... > ... <!-- The main/home activity (it has no parent activity) --> <activity android:name="com.example.myfirstapp.MainActivity" ...> ... </activity> <!-- A child of the main activity --> <activity android:name="com.example.myfirstapp.DisplayMessageActivity" android:label="@string/title_activity_display_message" android:parentActivityName="com.example.myfirstapp.MainActivity" > <!-- The meta-data element is needed for versions lower than 4.1 --> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value="com.example.myfirstapp.MainActivity" /> </activity> </application>
With the parent activity declared this way, you can use the
NavUtils
APIs to synthesize a new back stack by identifying which
activity is the appropriate parent for each activity.
Create back stack when starting the activity
Adding activities to the back stack begins upon the event that takes the user into your app.
That is, instead of calling startActivity()
, use the
TaskStackBuilder
APIs to define each activity that should
be placed into a new back stack. Then begin the target activity by calling startActivities()
, or create the
appropriate PendingIntent
by calling getPendingIntent()
.
For example, when a notification takes the user to an activity deep in your app hierarchy,
you can use this code to create a PendingIntent
that starts an activity and inserts a new back stack into the target task:
// Intent for the activity to open when user selects the notification Intent detailsIntent = new Intent(this, DetailsActivity.class); // Use TaskStackBuilder to build the back stack and get the PendingIntent PendingIntent pendingIntent = TaskStackBuilder.create(this) // add all of DetailsActivity's parents to the stack, // followed by DetailsActivity itself .addNextIntentWithParentStack(upIntent) .getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); NotificationCompat.Builder builder = new NotificationCompat.Builder(this); builder.setContentIntent(pendingIntent); ...
The resulting PendingIntent
specifies not only the activity to
start (as defined by detailsIntent
), but also the back stack that should be inserted
into the task (all parents of the DetailsActivity
defined by detailsIntent
).
So when the DetailsActivity
starts, pressing Back
navigates backward through each of the DetailsActivity
class's parent activities.
Note: In order for the addNextIntentWithParentStack()
method to work,
you must declare the logical parent of each activity in your manifest file, using the
android:parentActivityName
attribute (and corresponding <meta-data>
element)
as described above.
Implement Back Navigation for Fragments
When using fragments in your app, individual FragmentTransaction
objects may represent context changes that should be added to the back stack. For example, if you
are implementing a master/detail flow on a handset by
swapping out fragments, you should ensure that pressing the Back button on a detail
screen returns the user to the master screen. To do so, call addToBackStack()
before you commit
the transaction:
// Works with either the framework FragmentManager or the // support package FragmentManager (getSupportFragmentManager). getSupportFragmentManager().beginTransaction() .add(detailFragment, "detail") // Add this transaction to the back stack .addToBackStack() .commit();
When there are FragmentTransaction
objects on the back stack and the user
presses the Back button,
the FragmentManager
pops the most recent transaction off the back stack and
performs the reverse action (such as removing a fragment if the transaction added it).
Note: You should not add transactions to the back stack when the transaction is for horizontal navigation (such as when switching tabs) or when modifying the content appearance (such as when adjusting filters). For more information, about when Back navigation is appropriate, see the Navigation design guide.
If your application updates other user interface elements to reflect the current state of your
fragments, such as the action bar, remember to update the UI when you commit the transaction. You
should update your user interface after the back stack changes in addition to
when you commit the transaction. You can listen for when a FragmentTransaction
is reverted by setting up an FragmentManager.OnBackStackChangedListener
:
getSupportFragmentManager().addOnBackStackChangedListener( new FragmentManager.OnBackStackChangedListener() { public void onBackStackChanged() { // Update your UI here. } });
Implement Back Navigation for WebViews
If a part of your application is contained in a WebView
, it may be
appropriate for Back to traverse browser history. To do so, you can override onBackPressed()
and proxy to the
WebView
if it has history state:
@Override public void onBackPressed() { if (mWebView.canGoBack()) { mWebView.goBack(); return; } // Otherwise defer to system default behavior. super.onBackPressed(); }
Be careful when using this mechanism with highly dynamic web pages that can grow a large history. Pages that generate an extensive history, such as those that make frequent changes to the document hash, may make it tedious for users to get out of your activity.
For more information about using WebView
, read Building Web Apps in WebView.