Home | History | Annotate | Download | only in implementing-navigation
      1 page.title=Providing Proper Back Navigation
      2 page.tags="back navigation","NavUtils","TaskStackBuilder"
      3 
      4 trainingnavtop=true
      5 
      6 @jd:body
      7 
      8 <div id="tb-wrapper">
      9 <div id="tb">
     10 
     11 <h2>This lesson teaches you to:</h2>
     12 <ol>
     13   <li><a href="#SynthesizeBackStack">Synthesize a new Back Stack for Deep Links</a></li>
     14   <li><a href="#back-fragments">Implement Back Navigation for Fragments</a></li>
     15   <li><a href="#back-webviews">Implement Back Navigation for WebViews</a></li>
     16 </ol>
     17 
     18 <h2>You should also read</h2>
     19 <ul>
     20   <li><a href="{@docRoot}training/design-navigation/ancestral-temporal.html">Providing Ancestral and Temporal Navigation</a></li>
     21   <li><a href="{@docRoot}guide/components/tasks-and-back-stack.html">Tasks and Back Stack</a></li>
     22   <li><a href="{@docRoot}design/patterns/navigation.html">Android Design: Navigation</a></li>
     23 </ul>
     24 
     25 </div>
     26 </div>
     27 
     28 
     29 <p><em>Back</em> navigation is how users move backward through the history of screens
     30 they previously visited. All Android devices provide a <em>Back</em> button for this
     31 type of navigation, so <strong>your app should not add a Back button to the UI</strong>.</p>
     32 
     33 <p>In almost all situations, the system maintains a back stack of activities while the user
     34 navigates your application. This allows the system to properly navigate backward when the user
     35 presses the <em>Back</em> button. However, there are a few cases in which your app should manually
     36 specify the <em>Back</em> behavior in order to provide the best user experience.</p>
     37 
     38 <div class="note design">
     39 <p><strong>Back Navigation Design</strong></p>
     40 <p>Before continuing with this document, you should understand the
     41 concepts and principles for <em>Back</em> navigation as described in
     42 the <a href="{@docRoot}design/patterns/navigation.html">Navigation</a> design
     43 guide.</p>
     44 </div>
     45 
     46 <p>Navigation patterns that require you to manually specify the <em>Back</em> behavior include:</p>
     47 <ul>
     48   <li>When the user enters a deep-level activity directly from a <a
     49     href="{@docRoot}guide/topics/ui/notifiers/notifications.html">notification</a>, an <a
     50     href="{@docRoot}guide/topics/appwidgets/index.html">app widget</a>, or the <a
     51     href="{@docRoot}training/implementing-navigation/nav-drawer.html">navigation drawer</a>.</li>
     52   <li>Certain cases in which the user navigates between <a
     53     href="{@docRoot}guide/components/fragments.html">fragments</a>.</li>
     54   <li>When the user navigates web pages in a {@link android.webkit.WebView}.</li>
     55 </ul>
     56 
     57 <p>How to implement proper <em>Back</em> navigation in these situations is described
     58 in the following sections.</p>
     59 
     60 
     61 
     62 <h2 id="SynthesizeBackStack">Synthesize a new Back Stack for Deep Links</h2>
     63 
     64 <p>Ordinarily, the system incrementally builds the back stack as the user navigates from one
     65 activity to the next. However, when the user enters your app with a <em>deep link</em> that
     66 starts the activity in its own task, it's necessary for you to synthesize a new
     67 back stack because the activity is running in a new task without any back stack at all.</p>
     68 
     69 <p>For example, when a notification takes the user to an activity deep in your app hierarchy,
     70 you should add activities into your task's back stack so that pressing <em>Back</em> navigates
     71 up the app hierarchy instead of exiting the app. This pattern is described further in the
     72 <a href="{@docRoot}design/patterns/navigation.html#into-your-app"
     73 >Navigation</a> design guide.</p>
     74 
     75 
     76 <h3 id="SpecifyParent">Specify parent activities in the manifest</h3>
     77 
     78 <p>Beginning in Android 4.1 (API level 16), you can declare the logical parent of each
     79 activity by specifying the <a
     80 href="{@docRoot}guide/topics/manifest/activity-element.html#parent">{@code
     81 android:parentActivityName}</a> attribute
     82 in the <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
     83 &lt;activity>}</a> element. This allows the system to facilitate navigation patterns
     84 because it can determine the logical <em>Back</em> or <em>Up</em> navigation path with this
     85 information.</p>
     86 
     87 <p>If your app supports Android 4.0 and lower, include the
     88 <a href="{@docRoot}tools/support-library/index.html">Support Library</a> with your app and
     89 add a <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code &lt;meta-data>}</a>
     90 element inside the <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
     91 &lt;activity>}</a>. Then specify the parent activity as the value
     92 for {@code android.support.PARENT_ACTIVITY}, matching the <a
     93 href="{@docRoot}guide/topics/manifest/activity-element.html#parent">{@code
     94 android:parentActivityName}</a> attribute.</p>
     95 
     96 <p>For example:</p>
     97 
     98 <pre>
     99 &lt;application ... >
    100     ...
    101     &lt;!-- The main/home activity (it has no parent activity) -->
    102     &lt;activity
    103         android:name="com.example.myfirstapp.MainActivity" ...>
    104         ...
    105     &lt;/activity>
    106     &lt;!-- A child of the main activity -->
    107     &lt;activity
    108         android:name="com.example.myfirstapp.DisplayMessageActivity"
    109         android:label="&#64;string/title_activity_display_message"
    110         android:parentActivityName="com.example.myfirstapp.MainActivity" >
    111         &lt;!-- The meta-data element is needed for versions lower than 4.1 -->
    112         &lt;meta-data
    113             android:name="android.support.PARENT_ACTIVITY"
    114             android:value="com.example.myfirstapp.MainActivity" />
    115     &lt;/activity>
    116 &lt;/application>
    117 </pre>
    118 
    119 <p>With the parent activity declared this way, you can use the
    120 {@link android.support.v4.app.NavUtils} APIs to synthesize a new back stack by identifying which
    121 activity is the appropriate parent for each activity.</p>
    122 
    123 
    124 
    125 <h3 id="CreateBackStack">Create back stack when starting the activity</h3>
    126 
    127 <p>Adding activities to the back stack begins upon the event that takes the user into your app.
    128 That is, instead of calling {@link android.content.Context#startActivity startActivity()}, use the
    129 {@link android.support.v4.app.TaskStackBuilder} APIs to define each activity that should
    130 be placed into a new back stack. Then begin the target activity by calling {@link
    131 android.support.v4.app.TaskStackBuilder#startActivities startActivities()}, or create the
    132 appropriate {@link android.app.PendingIntent} by calling {@link
    133 android.support.v4.app.TaskStackBuilder#getPendingIntent getPendingIntent()}.</p>
    134 
    135 <p>For example, when a notification takes the user to an activity deep in your app hierarchy,
    136 you can use this code to create a {@link android.app.PendingIntent}
    137 that starts an activity and inserts a new back stack into the target task:</p>
    138 
    139 <pre>
    140 // Intent for the activity to open when user selects the notification
    141 Intent detailsIntent = new Intent(this, DetailsActivity.class);
    142 
    143 // Use TaskStackBuilder to build the back stack and get the PendingIntent
    144 PendingIntent pendingIntent =
    145         TaskStackBuilder.create(this)
    146                         // add all of DetailsActivity's parents to the stack,
    147                         // followed by DetailsActivity itself
    148                         .addNextIntentWithParentStack(upIntent)
    149                         .getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
    150 
    151 NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
    152 builder.setContentIntent(pendingIntent);
    153 ...
    154 </pre>
    155 
    156 <p>The resulting {@link android.app.PendingIntent} specifies not only the activity to
    157 start (as defined by {@code detailsIntent}), but also the back stack that should be inserted
    158 into the task (all parents of the {@code DetailsActivity} defined by {@code detailsIntent}).
    159 So when the {@code DetailsActivity} starts, pressing <em>Back</em>
    160 navigates backward through each of the {@code DetailsActivity} class's parent activities.</p>
    161 
    162 <p class="note"><strong>Note:</strong> In order for the {@link
    163 android.support.v4.app.TaskStackBuilder#addNextIntentWithParentStack addNextIntentWithParentStack()}
    164 method to work,
    165 you must declare the logical parent of each activity in your manifest file, using the
    166 <a href="{@docRoot}guide/topics/manifest/activity-element.html#parent">{@code
    167 android:parentActivityName}</a> attribute (and corresponding <a
    168 href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code &lt;meta-data>}</a> element)
    169 as described above.</p>
    170 
    171 
    172 
    173 
    174 
    175 <h2 id="back-fragments">Implement Back Navigation for Fragments</h2>
    176 
    177 <p>When using fragments in your app, individual {@link android.app.FragmentTransaction}
    178 objects may represent context changes that should be added to the back stack. For example, if you
    179 are implementing a <a href="descendant.html#master-detail">master/detail flow</a> on a handset by
    180 swapping out fragments, you should ensure that pressing the <em>Back</em> button on a detail
    181 screen returns the user to the master screen. To do so, call {@link
    182 android.app.FragmentTransaction#addToBackStack addToBackStack()} before you commit
    183 the transaction:</p>
    184 
    185 <pre>
    186 // Works with either the framework FragmentManager or the
    187 // support package FragmentManager (getSupportFragmentManager).
    188 getSupportFragmentManager().beginTransaction()
    189                            .add(detailFragment, "detail")
    190                            // Add this transaction to the back stack
    191                            .addToBackStack()
    192                            .commit();
    193 </pre>
    194 
    195 <p>When there are {@link android.app.FragmentTransaction} objects on the back stack and the user
    196 presses the <em>Back</em> button,
    197 the {@link android.app.FragmentManager} pops the most recent transaction off the back stack and
    198 performs the reverse action (such as removing a fragment if the transaction added it).</p>
    199 
    200 <p class="note"><strong>Note:</strong> You <strong>should not add transactions to the back
    201 stack</strong> when the transaction is for horizontal navigation (such as when switching tabs)
    202 or when modifying the content appearance (such as when adjusting filters). For more information,
    203 about when <em>Back</em> navigation is appropriate,
    204 see the <a href="{@docRoot}design/patterns/navigation.html">Navigation</a> design guide.</p>
    205 
    206 <p>If your application updates other user interface elements to reflect the current state of your
    207 fragments, such as the action bar, remember to update the UI when you commit the transaction. You
    208 should update your user interface after the back stack changes in addition to
    209 when you commit the transaction. You can listen for when a {@link android.app.FragmentTransaction}
    210 is reverted by setting up an {@link android.app.FragmentManager.OnBackStackChangedListener}:</p>
    211 
    212 <pre>
    213 getSupportFragmentManager().addOnBackStackChangedListener(
    214         new FragmentManager.OnBackStackChangedListener() {
    215             public void onBackStackChanged() {
    216                 // Update your UI here.
    217             }
    218         });
    219 </pre>
    220 
    221 
    222 
    223 <h2 id="back-webviews">Implement Back Navigation for WebViews</h2>
    224 
    225 <p>If a part of your application is contained in a {@link android.webkit.WebView}, it may be
    226 appropriate for <em>Back</em> to traverse browser history. To do so, you can override {@link
    227 android.app.Activity#onBackPressed onBackPressed()} and proxy to the
    228 {@link android.webkit.WebView} if it has history state:</p>
    229 
    230 <pre>
    231 {@literal @}Override
    232 public void onBackPressed() {
    233     if (mWebView.canGoBack()) {
    234         mWebView.goBack();
    235         return;
    236     }
    237 
    238     // Otherwise defer to system default behavior.
    239     super.onBackPressed();
    240 }
    241 </pre>
    242 
    243 <p>Be careful when using this mechanism with highly dynamic web pages that can grow a large
    244 history. Pages that generate an extensive history, such as those that make frequent changes to
    245 the document hash, may make it tedious for users to get out of your activity.</p>
    246 
    247 <p>For more information about using {@link android.webkit.WebView}, read <a
    248 href="{@docRoot}guide/webapps/webview.html">Building Web Apps in WebView</a>.
    249