blob: e7366483e21bea6e4fa0d3b8087fe206adc3f435 [file] [log] [blame]
Scott Main7c840552013-03-26 18:53:01 -07001page.title=Providing Proper Back Navigation
Joe Fernandez33baa5a2013-11-14 11:41:19 -08002page.tags=back navigation,NavUtils,TaskStackBuilder
Roman Nurik19266f72012-03-12 21:48:47 -07003
4trainingnavtop=true
Roman Nurik19266f72012-03-12 21:48:47 -07005
6@jd:body
7
8<div id="tb-wrapper">
9<div id="tb">
10
11<h2>This lesson teaches you to:</h2>
12<ol>
Scott Main7c840552013-03-26 18:53:01 -070013 <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>
Roman Nurik19266f72012-03-12 21:48:47 -070016</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>
Scott Main50e990c2012-06-21 17:14:39 -070021 <li><a href="{@docRoot}guide/components/tasks-and-back-stack.html">Tasks and Back Stack</a></li>
Roman Nurik19266f72012-03-12 21:48:47 -070022 <li><a href="{@docRoot}design/patterns/navigation.html">Android Design: Navigation</a></li>
23</ul>
24
25</div>
26</div>
27
28
Scott Main7c840552013-03-26 18:53:01 -070029<p><em>Back</em> navigation is how users move backward through the history of screens
30they previously visited. All Android devices provide a <em>Back</em> button for this
31type of navigation, so <strong>your app should not add a Back button to the UI</strong>.</p>
Roman Nurik19266f72012-03-12 21:48:47 -070032
Scott Main7c840552013-03-26 18:53:01 -070033<p>In almost all situations, the system maintains a back stack of activities while the user
34navigates your application. This allows the system to properly navigate backward when the user
35presses the <em>Back</em> button. However, there are a few cases in which your app should manually
36specify 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
41concepts and principles for <em>Back</em> navigation as described in
42the <a href="{@docRoot}design/patterns/navigation.html">Navigation</a> design
43guide.</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
58in the following sections.</p>
Roman Nurik19266f72012-03-12 21:48:47 -070059
60
Roman Nurik19266f72012-03-12 21:48:47 -070061
Scott Main7c840552013-03-26 18:53:01 -070062<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
65activity to the next. However, when the user enters your app with a <em>deep link</em> that
66starts the activity in its own task, it's necessary for you to synthesize a new
67back 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,
70you should add activities into your task's back stack so that pressing <em>Back</em> navigates
71up 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
79activity by specifying the <a
80href="{@docRoot}guide/topics/manifest/activity-element.html#parent">{@code
81android:parentActivityName}</a> attribute
82in the <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
83&lt;activity>}</a> element. This allows the system to facilitate navigation patterns
84because it can determine the logical <em>Back</em> or <em>Up</em> navigation path with this
85information.</p>
86
87<p>If your app supports Android 4.0 and lower, include the
Scott Main4e2c9dc2013-07-23 19:35:17 -070088<a href="{@docRoot}tools/support-library/index.html">Support Library</a> with your app and
Scott Main7c840552013-03-26 18:53:01 -070089add a <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code &lt;meta-data>}</a>
90element inside the <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
91&lt;activity>}</a>. Then specify the parent activity as the value
92for {@code android.support.PARENT_ACTIVITY}, matching the <a
93href="{@docRoot}guide/topics/manifest/activity-element.html#parent">{@code
94android: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
121activity 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.
128That 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
130be placed into a new back stack. Then begin the target activity by calling {@link
131android.support.v4.app.TaskStackBuilder#startActivities startActivities()}, or create the
132appropriate {@link android.app.PendingIntent} by calling {@link
133android.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,
136you can use this code to create a {@link android.app.PendingIntent}
137that 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
141Intent detailsIntent = new Intent(this, DetailsActivity.class);
142
143// Use TaskStackBuilder to build the back stack and get the PendingIntent
144PendingIntent 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
151NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
152builder.setContentIntent(pendingIntent);
153...
154</pre>
155
156<p>The resulting {@link android.app.PendingIntent} specifies not only the activity to
157start (as defined by {@code detailsIntent}), but also the back stack that should be inserted
158into the task (all parents of the {@code DetailsActivity} defined by {@code detailsIntent}).
159So when the {@code DetailsActivity} starts, pressing <em>Back</em>
160navigates 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
163android.support.v4.app.TaskStackBuilder#addNextIntentWithParentStack addNextIntentWithParentStack()}
164method to work,
165you 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
167android:parentActivityName}</a> attribute (and corresponding <a
168href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code &lt;meta-data>}</a> element)
169as 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}
178objects may represent context changes that should be added to the back stack. For example, if you
179are implementing a <a href="descendant.html#master-detail">master/detail flow</a> on a handset by
180swapping out fragments, you should ensure that pressing the <em>Back</em> button on a detail
181screen returns the user to the master screen. To do so, call {@link
182android.app.FragmentTransaction#addToBackStack addToBackStack()} before you commit
183the transaction:</p>
Roman Nurik19266f72012-03-12 21:48:47 -0700184
185<pre>
186// Works with either the framework FragmentManager or the
187// support package FragmentManager (getSupportFragmentManager).
Scott Main7c840552013-03-26 18:53:01 -0700188getSupportFragmentManager().beginTransaction()
189 .add(detailFragment, "detail")
190 // Add this transaction to the back stack
191 .addToBackStack()
192 .commit();
Roman Nurik19266f72012-03-12 21:48:47 -0700193</pre>
194
Scott Main7c840552013-03-26 18:53:01 -0700195<p>When there are {@link android.app.FragmentTransaction} objects on the back stack and the user
196presses the <em>Back</em> button,
197the {@link android.app.FragmentManager} pops the most recent transaction off the back stack and
198performs the reverse action (such as removing a fragment if the transaction added it).</p>
Roman Nurik19266f72012-03-12 21:48:47 -0700199
Scott Main7c840552013-03-26 18:53:01 -0700200<p class="note"><strong>Note:</strong> You <strong>should not add transactions to the back
201stack</strong> when the transaction is for horizontal navigation (such as when switching tabs)
202or when modifying the content appearance (such as when adjusting filters). For more information,
203about when <em>Back</em> navigation is appropriate,
204see 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
207fragments, such as the action bar, remember to update the UI when you commit the transaction. You
208should update your user interface after the back stack changes in addition to
209when you commit the transaction. You can listen for when a {@link android.app.FragmentTransaction}
210is reverted by setting up an {@link android.app.FragmentManager.OnBackStackChangedListener}:</p>
Roman Nurik19266f72012-03-12 21:48:47 -0700211
212<pre>
Scott Main7c840552013-03-26 18:53:01 -0700213getSupportFragmentManager().addOnBackStackChangedListener(
Roman Nurik19266f72012-03-12 21:48:47 -0700214 new FragmentManager.OnBackStackChangedListener() {
215 public void onBackStackChanged() {
216 // Update your UI here.
217 }
218 });
219</pre>
220
Roman Nurik19266f72012-03-12 21:48:47 -0700221
Scott Main7c840552013-03-26 18:53:01 -0700222
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
226appropriate for <em>Back</em> to traverse browser history. To do so, you can override {@link
227android.app.Activity#onBackPressed onBackPressed()} and proxy to the
228{@link android.webkit.WebView} if it has history state:</p>
Roman Nurik19266f72012-03-12 21:48:47 -0700229
230<pre>
231{@literal @}Override
232public 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
Scott Main7c840552013-03-26 18:53:01 -0700243<p>Be careful when using this mechanism with highly dynamic web pages that can grow a large
244history. Pages that generate an extensive history, such as those that make frequent changes to
245the 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
248href="{@docRoot}guide/webapps/webview.html">Building Web Apps in WebView</a>.