diff options
Diffstat (limited to 'docs/html/training/implementing-navigation/temporal.jd')
| -rw-r--r-- | docs/html/training/implementing-navigation/temporal.jd | 215 |
1 files changed, 190 insertions, 25 deletions
diff --git a/docs/html/training/implementing-navigation/temporal.jd b/docs/html/training/implementing-navigation/temporal.jd index 1c41732..0719ba6 100644 --- a/docs/html/training/implementing-navigation/temporal.jd +++ b/docs/html/training/implementing-navigation/temporal.jd @@ -1,12 +1,7 @@ -page.title=Implementing Temporal Navigation -parent.title=Implementing Effective Navigation -parent.link=index.html +page.title=Providing Proper Back Navigation +page.tags="back navigation","NavUtils","TaskStackBuilder" trainingnavtop=true -previous.title=Implementing Ancestral Navigation -previous.link=ancestral.html -next.title=Implementing Descendant Navigation -next.link=descendant.html @jd:body @@ -15,8 +10,9 @@ next.link=descendant.html <h2>This lesson teaches you to:</h2> <ol> - <li><a href="#back-fragments">Implement <em>Back</em> Navigation with Fragments</a></li> - <li><a href="#back-webviews">Implement <em>Back</em> Navigation with WebViews</a></li> + <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> @@ -30,32 +26,191 @@ next.link=descendant.html </div> -<p><em>Temporal navigation</em> is navigation to previously visited screens. Users can visit previous screens by pressing the device <em>Back</em> button. This user interface pattern is described further in <a href="{@docRoot}training/design-navigation/ancestral-temporal.html">Providing Ancestral and Temporal Navigation</a> in <em>Designing Effective Navigation</em> and in <a href="{@docRoot}design/patterns/navigation.html">Android Design: Navigation</a>.</p> +<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>Android handles basic <em>Back</em> navigation for you (see <a href="{@docRoot}guide/components/tasks-and-back-stack.html">Tasks and Back Stack</a> for details on this behavior). This lesson discusses a number of cases where applications should provide specialized logic for the <em>Back</em> button.</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> -<h2 id="back-fragments">Implement <em>Back</em> Navigation with Fragments</h2> -<p>When using fragments in your application, individual {@link android.app.FragmentTransaction} objects can 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 (thus emulating a {@link android.app.Activity#startActivity startActivity()} call), you should ensure that pressing the <em>Back</em> button on a detail screen returns the user to the master screen. To do so, you can use {@link android.app.FragmentTransaction#addToBackStack addToBackStack()}:</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). -getFragmentManager().beginTransaction() - .add(detailFragment, "detail") - - // Add this transaction to the back stack and commit. - .addToBackStack() - .commit(); +getSupportFragmentManager().beginTransaction() + .add(detailFragment, "detail") + // Add this transaction to the back stack + .addToBackStack() + .commit(); </pre> -<p>The activity's {@link android.app.FragmentManager} handles <em>Back</em> button presses if there are {@link android.app.FragmentTransaction} objects on the back stack. When this happens, the {@link android.app.FragmentManager} pops the most recent transaction off the back stack and performs the reverse action (e.g., removing a fragment if the transaction added it).</p> +<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>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 fragment manager back stack changes in addition to when you commit the transaction. You can listen for when a <code>FragmentTransaction</code> is reverted by setting up an {@link android.app.FragmentManager.OnBackStackChangedListener}:</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> -getFragmentManager().addOnBackStackChangedListener( +getSupportFragmentManager().addOnBackStackChangedListener( new FragmentManager.OnBackStackChangedListener() { public void onBackStackChanged() { // Update your UI here. @@ -63,9 +218,14 @@ getFragmentManager().addOnBackStackChangedListener( }); </pre> -<h2 id="back-webviews">Implement <em>Back</em> Navigation with 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 <code>WebView</code> if it has history state:</p> + +<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 @@ -80,4 +240,9 @@ public void 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>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>. |
