4e2c9dc74b
Change-Id: I173e3690148e5de3020bfdca8087906faa56b13b
249 lines
11 KiB
Plaintext
249 lines
11 KiB
Plaintext
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>.
|