| 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/support-library/index.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>. |