| page.title=Providing Proper Back Navigation | |
| page.tags="back navigation","NavUtils","TaskStackBuilder" | |
| trainingnavtop=true | |
| @jd:body | |
| <div id="tb-wrapper"> | |
| <div id="tb"> | |
| <h2>This lesson teaches you to:</h2> | |
| <ol> | |
| <li><a href="#SynthesizeBackStack">Synthesize a new Back Stack for Deep Links</a></li> | |
| <li><a href="#back-fragments">Implement Back Navigation for Fragments</a></li> | |
| <li><a href="#back-webviews">Implement Back Navigation for WebViews</a></li> | |
| </ol> | |
| <h2>You should also read</h2> | |
| <ul> | |
| <li><a href="{@docRoot}training/design-navigation/ancestral-temporal.html">Providing Ancestral and Temporal Navigation</a></li> | |
| <li><a href="{@docRoot}guide/components/tasks-and-back-stack.html">Tasks and Back Stack</a></li> | |
| <li><a href="{@docRoot}design/patterns/navigation.html">Android Design: Navigation</a></li> | |
| </ul> | |
| </div> | |
| </div> | |
| <p><em>Back</em> navigation is how users move backward through the history of screens | |
| they previously visited. All Android devices provide a <em>Back</em> button for this | |
| type of navigation, so <strong>your app should not add a Back button to the UI</strong>.</p> | |
| <p>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 <em>Back</em> button. However, there are a few cases in which your app should manually | |
| specify the <em>Back</em> behavior in order to provide the best user experience.</p> | |
| <div class="note design"> | |
| <p><strong>Back Navigation Design</strong></p> | |
| <p>Before continuing with this document, you should understand the | |
| concepts and principles for <em>Back</em> navigation as described in | |
| the <a href="{@docRoot}design/patterns/navigation.html">Navigation</a> design | |
| guide.</p> | |
| </div> | |
| <p>Navigation patterns that require you to manually specify the <em>Back</em> behavior include:</p> | |
| <ul> | |
| <li>When the user enters a deep-level activity directly from a <a | |
| href="{@docRoot}guide/topics/ui/notifiers/notifications.html">notification</a>, an <a | |
| href="{@docRoot}guide/topics/appwidgets/index.html">app widget</a>, or the <a | |
| href="{@docRoot}training/implementing-navigation/nav-drawer.html">navigation drawer</a>.</li> | |
| <li>Certain cases in which the user navigates between <a | |
| href="{@docRoot}guide/components/fragments.html">fragments</a>.</li> | |
| <li>When the user navigates web pages in a {@link android.webkit.WebView}.</li> | |
| </ul> | |
| <p>How to implement proper <em>Back</em> navigation in these situations is described | |
| in the following sections.</p> | |
| <h2 id="SynthesizeBackStack">Synthesize a new Back Stack for Deep Links</h2> | |
| <p>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 <em>deep link</em> 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.</p> | |
| <p>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 <em>Back</em> navigates | |
| up the app hierarchy instead of exiting the app. This pattern is described further in the | |
| <a href="{@docRoot}design/patterns/navigation.html#into-your-app" | |
| >Navigation</a> design guide.</p> | |
| <h3 id="SpecifyParent">Specify parent activities in the manifest</h3> | |
| <p>Beginning in Android 4.1 (API level 16), you can declare the logical parent of each | |
| activity by specifying the <a | |
| href="{@docRoot}guide/topics/manifest/activity-element.html#parent">{@code | |
| android:parentActivityName}</a> attribute | |
| in the <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code | |
| <activity>}</a> element. This allows the system to facilitate navigation patterns | |
| because it can determine the logical <em>Back</em> or <em>Up</em> navigation path with this | |
| information.</p> | |
| <p>If your app supports Android 4.0 and lower, include the | |
| <a href="{@docRoot}tools/extras/support-library.html">Support Library</a> with your app and | |
| add a <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code <meta-data>}</a> | |
| element inside the <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code | |
| <activity>}</a>. Then specify the parent activity as the value | |
| for {@code android.support.PARENT_ACTIVITY}, matching the <a | |
| href="{@docRoot}guide/topics/manifest/activity-element.html#parent">{@code | |
| android:parentActivityName}</a> attribute.</p> | |
| <p>For example:</p> | |
| <pre> | |
| <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> | |
| </pre> | |
| <p>With the parent activity declared this way, you can use the | |
| {@link android.support.v4.app.NavUtils} APIs to synthesize a new back stack by identifying which | |
| activity is the appropriate parent for each activity.</p> | |
| <h3 id="CreateBackStack">Create back stack when starting the activity</h3> | |
| <p>Adding activities to the back stack begins upon the event that takes the user into your app. | |
| That is, instead of calling {@link android.content.Context#startActivity startActivity()}, use the | |
| {@link android.support.v4.app.TaskStackBuilder} APIs to define each activity that should | |
| be placed into a new back stack. Then begin the target activity by calling {@link | |
| android.support.v4.app.TaskStackBuilder#startActivities startActivities()}, or create the | |
| appropriate {@link android.app.PendingIntent} by calling {@link | |
| android.support.v4.app.TaskStackBuilder#getPendingIntent getPendingIntent()}.</p> | |
| <p>For example, when a notification takes the user to an activity deep in your app hierarchy, | |
| you can use this code to create a {@link android.app.PendingIntent} | |
| that starts an activity and inserts a new back stack into the target task:</p> | |
| <pre> | |
| // 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); | |
| ... | |
| </pre> | |
| <p>The resulting {@link android.app.PendingIntent} specifies not only the activity to | |
| start (as defined by {@code detailsIntent}), but also the back stack that should be inserted | |
| into the task (all parents of the {@code DetailsActivity} defined by {@code detailsIntent}). | |
| So when the {@code DetailsActivity} starts, pressing <em>Back</em> | |
| navigates backward through each of the {@code DetailsActivity} class's parent activities.</p> | |
| <p class="note"><strong>Note:</strong> In order for the {@link | |
| android.support.v4.app.TaskStackBuilder#addNextIntentWithParentStack addNextIntentWithParentStack()} | |
| method to work, | |
| you must declare the logical parent of each activity in your manifest file, using the | |
| <a href="{@docRoot}guide/topics/manifest/activity-element.html#parent">{@code | |
| android:parentActivityName}</a> attribute (and corresponding <a | |
| href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code <meta-data>}</a> element) | |
| as described above.</p> | |
| <h2 id="back-fragments">Implement Back Navigation for Fragments</h2> | |
| <p>When using fragments in your app, individual {@link android.app.FragmentTransaction} | |
| objects may represent context changes that should be added to the back stack. For example, if you | |
| are implementing a <a href="descendant.html#master-detail">master/detail flow</a> on a handset by | |
| swapping out fragments, you should ensure that pressing the <em>Back</em> button on a detail | |
| screen returns the user to the master screen. To do so, call {@link | |
| android.app.FragmentTransaction#addToBackStack addToBackStack()} before you commit | |
| the transaction:</p> | |
| <pre> | |
| // 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(); | |
| </pre> | |
| <p>When there are {@link android.app.FragmentTransaction} objects on the back stack and the user | |
| presses the <em>Back</em> button, | |
| the {@link android.app.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).</p> | |
| <p class="note"><strong>Note:</strong> You <strong>should not add transactions to the back | |
| stack</strong> 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 <em>Back</em> navigation is appropriate, | |
| see the <a href="{@docRoot}design/patterns/navigation.html">Navigation</a> design guide.</p> | |
| <p>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 {@link android.app.FragmentTransaction} | |
| is reverted by setting up an {@link android.app.FragmentManager.OnBackStackChangedListener}:</p> | |
| <pre> | |
| getSupportFragmentManager().addOnBackStackChangedListener( | |
| new FragmentManager.OnBackStackChangedListener() { | |
| public void onBackStackChanged() { | |
| // Update your UI here. | |
| } | |
| }); | |
| </pre> | |
| <h2 id="back-webviews">Implement Back Navigation for WebViews</h2> | |
| <p>If a part of your application is contained in a {@link android.webkit.WebView}, it may be | |
| appropriate for <em>Back</em> to traverse browser history. To do so, you can override {@link | |
| android.app.Activity#onBackPressed onBackPressed()} and proxy to the | |
| {@link android.webkit.WebView} if it has history state:</p> | |
| <pre> | |
| {@literal @}Override | |
| public void onBackPressed() { | |
| if (mWebView.canGoBack()) { | |
| mWebView.goBack(); | |
| return; | |
| } | |
| // Otherwise defer to system default behavior. | |
| super.onBackPressed(); | |
| } | |
| </pre> | |
| <p>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.</p> | |
| <p>For more information about using {@link android.webkit.WebView}, read <a | |
| href="{@docRoot}guide/webapps/webview.html">Building Web Apps in WebView</a>. |