Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 1 | page.title=Fragments |
Scott Main | b70afd3 | 2011-02-08 14:05:54 -0800 | [diff] [blame] | 2 | parent.title=Activities |
| 3 | parent.link=activities.html |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 4 | @jd:body |
| 5 | |
| 6 | <div id="qv-wrapper"> |
| 7 | <div id="qv"> |
| 8 | |
| 9 | <h2>Quickview</h2> |
| 10 | <ul> |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 11 | <li>Fragments decompose application functionality and UI into reusable modules</li> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 12 | <li>Add multiple fragments to a screen to avoid switching activities</li> |
| 13 | <li>Fragments have their own lifecycle, state, and back stack</li> |
Scott Main | b6cf4b7 | 2011-10-27 12:49:15 -0700 | [diff] [blame] | 14 | <li>Fragments require API Level 11 or greater</li> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 15 | </ul> |
| 16 | |
| 17 | <h2>In this document</h2> |
| 18 | <ol> |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 19 | <li><a href="#Design">Design Philosophy</a></li> |
| 20 | <li><a href="#Creating">Creating a Fragment</a> |
| 21 | <ol> |
| 22 | <li><a href="#UI">Adding a user interface</a></li> |
| 23 | <li><a href="#Adding">Adding a fragment to an activity</a></li> |
| 24 | </ol> |
| 25 | </li> |
| 26 | <li><a href="#Managing">Managing Fragments</a></li> |
| 27 | <li><a href="#Transactions">Performing Fragment Transactions</a></li> |
| 28 | <li><a href="#CommunicatingWithActivity">Communicating with the Activity</a> |
| 29 | <ol> |
| 30 | <li><a href="#EventCallbacks">Creating event callbacks to the activity</a></li> |
| 31 | <li><a href="#ActionBar">Adding items to the Action Bar</a></li> |
| 32 | </ol> |
| 33 | </li> |
| 34 | <li><a href="#Lifecycle">Handling the Fragment Lifecycle</a> |
| 35 | <ol> |
Scott Main | 9c9b9ad | 2011-12-29 11:28:38 -0800 | [diff] [blame] | 36 | <li><a href="#CoordinatingWithActivity">Coordinating with the activity lifecycle</a></li> |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 37 | </ol> |
| 38 | </li> |
| 39 | <li><a href="#Example">Example</a></li> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 40 | </ol> |
| 41 | |
| 42 | <h2>Key classes</h2> |
| 43 | <ol> |
| 44 | <li>{@link android.app.Fragment}</li> |
| 45 | <li>{@link android.app.FragmentManager}</li> |
| 46 | <li>{@link android.app.FragmentTransaction}</li> |
| 47 | </ol> |
| 48 | |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 49 | <h2>Related samples</h2> |
| 50 | <ol> |
| 51 | <li><a |
Scott Main | b6cf4b7 | 2011-10-27 12:49:15 -0700 | [diff] [blame] | 52 | href="{@docRoot}resources/samples/HoneycombGallery/index.html">Honeycomb Gallery</a></li> |
| 53 | <li><a |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 54 | href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/index.html#Fragment">ApiDemos</a></li> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 55 | </ol> |
Scott Main | b6cf4b7 | 2011-10-27 12:49:15 -0700 | [diff] [blame] | 56 | |
| 57 | <h2>See also</h2> |
| 58 | <ol> |
| 59 | <li><a href="{@docRoot}guide/practices/tablets-and-handsets.html">Supporting Tablets |
| 60 | and Handsets</a></li> |
| 61 | </ol> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 62 | </div> |
| 63 | </div> |
| 64 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 65 | <p>A {@link android.app.Fragment} represents a behavior or a portion of user interface in an |
| 66 | {@link android.app.Activity}. You can combine multiple fragments in a single activity to build a |
| 67 | multi-pane UI and reuse a fragment in multiple activities. You can think of a fragment as a |
| 68 | modular section of an activity, which has its own lifecycle, receives its own input events, and |
Scott Main | b6cf4b7 | 2011-10-27 12:49:15 -0700 | [diff] [blame] | 69 | which you can add or remove while the activity is running (sort of like a "sub activity" that |
| 70 | you can reuse in different activities).</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 71 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 72 | <p>A fragment must always be embedded in an activity and the fragment's lifecycle is directly |
Scott Main | 6027501 | 2011-01-21 18:36:07 -0800 | [diff] [blame] | 73 | affected by the host activity's lifecycle. For example, when the activity is paused, so are all |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 74 | fragments in it, and when the activity is destroyed, so are all fragments. However, while an |
| 75 | activity is running (it is in the <em>resumed</em> <a |
| 76 | href="{@docRoot}guide/topics/fundamentals/activities.html#Lifecycle">lifecycle state</a>), you can |
| 77 | manipulate each fragment independently, such as add or remove them. When you perform such a |
Scott Main | 6027501 | 2011-01-21 18:36:07 -0800 | [diff] [blame] | 78 | fragment transaction, you can also add it to a back stack that's managed by the |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 79 | activity—each back stack entry in the activity is a record of the fragment transaction that |
| 80 | occurred. The back stack allows the user to reverse a fragment transaction (navigate backwards), |
Scott Main | b6cf4b7 | 2011-10-27 12:49:15 -0700 | [diff] [blame] | 81 | by pressing the BACK button.</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 82 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 83 | <p>When you add a fragment as a part of your activity layout, it lives in a {@link |
Scott Main | b6cf4b7 | 2011-10-27 12:49:15 -0700 | [diff] [blame] | 84 | android.view.ViewGroup} inside the activity's view hierarchy and the fragment defines its own view |
| 85 | layout. |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 86 | You can insert a fragment into your activity layout by declaring the fragment in the activity's |
| 87 | layout file, as a {@code <fragment>} element, or from your application code by adding it to an |
| 88 | existing {@link android.view.ViewGroup}. However, a fragment is not required to be a part of the |
Scott Main | b6cf4b7 | 2011-10-27 12:49:15 -0700 | [diff] [blame] | 89 | activity layout; you may also use a fragment without its own UI as an invisible worker for the |
| 90 | activity.</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 91 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 92 | <p>This document describes how to build your application to use fragments, including |
| 93 | how fragments can maintain their state when added to the activity's back stack, share |
| 94 | events with the activity and other fragments in the activity, contribute to the activity's action |
| 95 | bar, and more.</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 96 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 97 | |
| 98 | <h2 id="Design">Design Philosophy</h2> |
| 99 | |
Scott Main | b6cf4b7 | 2011-10-27 12:49:15 -0700 | [diff] [blame] | 100 | <p>Android introduced fragments in Android 3.0 (API level 11), primarily to support more |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 101 | dynamic and flexible UI designs on large screens, such as tablets. Because a |
Scott Main | b6cf4b7 | 2011-10-27 12:49:15 -0700 | [diff] [blame] | 102 | tablet's screen is much larger than that of a handset, there's more room to combine and |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 103 | interchange UI components. Fragments allow such designs without the need for you to manage complex |
| 104 | changes to the view hierarchy. By dividing the layout of an activity into fragments, you become able |
| 105 | to modify the activity's appearance at runtime and preserve those changes in a back stack |
| 106 | that's managed by the activity.</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 107 | |
| 108 | <p>For example, a news application can use one fragment to show a list of articles on the |
| 109 | left and another fragment to display an article on the right—both fragments appear in one |
| 110 | activity, side by side, and each fragment has its own set of lifecycle callback methods and handle |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 111 | their own user input events. Thus, instead of using one activity to select an article and another |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 112 | activity to read the article, the user can select an article and read it all within the same |
Scott Main | b6cf4b7 | 2011-10-27 12:49:15 -0700 | [diff] [blame] | 113 | activity, as illustrated in the tablet layout in figure 1.</p> |
| 114 | |
| 115 | <p>You should design each fragment as a modular and reusable activity component. That is, because |
| 116 | each fragment defines its own layout and its own behavior with its own lifecycle callbacks, you can |
| 117 | include one fragment in multiple activities, so you should design for reuse and avoid directly |
| 118 | manipulating one fragment from another fragment. This is especially important because a modular |
| 119 | fragment allows you to change your fragment combinations for different screen sizes. When designing |
| 120 | your application to support both tablets and handsets, you can reuse your fragments in different |
| 121 | layout configurations to optimize the user experience based on the available screen space. For |
| 122 | example, on a handset, it might be necessary to separate fragments to provide a single-pane UI when |
| 123 | more than one cannot fit within the same activity.</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 124 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 125 | <img src="{@docRoot}images/fundamentals/fragments.png" alt="" /> |
Scott Main | b6cf4b7 | 2011-10-27 12:49:15 -0700 | [diff] [blame] | 126 | <p class="img-caption"><strong>Figure 1.</strong> An example of how two UI modules defined by |
| 127 | fragments can be combined into one activity for a tablet design, but separated for a |
| 128 | handset design.</p> |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 129 | |
| 130 | <p>For example—to continue with the news application example—the application can embed |
Scott Main | b6cf4b7 | 2011-10-27 12:49:15 -0700 | [diff] [blame] | 131 | two fragments in <em>Activity A</em>, when running on a tablet-sized device. However, on a |
| 132 | handset-sized screen, there's not be enough room for both fragments, so <em>Activity A</em> includes |
| 133 | only the fragment for the list of articles, and when the user selects an article, it starts |
| 134 | <em>Activity B</em>, which includes the second fragment to read the article. Thus, the application |
| 135 | supports both tablets and handsets by reusing fragments in different combinations, as illustrated in |
| 136 | figure 1.</p> |
| 137 | |
| 138 | <p>For more information about designing your application with different fragment combinations for |
| 139 | different screen configurations, see the guide to <a |
| 140 | href="{@docRoot}guide/practices/tablets-and-handsets.html">Supporting Tablets and Handsets</a>.</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 141 | |
| 142 | |
| 143 | |
| 144 | <h2 id="Creating">Creating a Fragment</h2> |
| 145 | |
Scott Main | 9c9b9ad | 2011-12-29 11:28:38 -0800 | [diff] [blame] | 146 | <div class="figure" style="width:327px"> |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 147 | <img src="{@docRoot}images/fragment_lifecycle.png" alt="" /> |
| 148 | <p class="img-caption"><strong>Figure 2.</strong> The lifecycle of a fragment (while its |
| 149 | activity is running).</p> |
| 150 | </div> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 151 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 152 | <p>To create a fragment, you must create a subclass of {@link android.app.Fragment} (or an existing |
| 153 | subclass of it). The {@link android.app.Fragment} class has code that looks a lot like |
| 154 | an {@link android.app.Activity}. It contains callback methods similar to an activity, such |
| 155 | as {@link android.app.Fragment#onCreate onCreate()}, {@link android.app.Fragment#onStart onStart()}, |
| 156 | {@link android.app.Fragment#onPause onPause()}, and {@link android.app.Fragment#onStop onStop()}. In |
| 157 | fact, if you're converting an existing Android application to use fragments, you might simply move |
| 158 | code from your activity's callback methods into the respective callback methods of your |
| 159 | fragment.</p> |
| 160 | |
| 161 | <p>Usually, you should implement at least the following lifecycle methods:</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 162 | |
| 163 | <dl> |
| 164 | <dt>{@link android.app.Fragment#onCreate onCreate()}</dt> |
| 165 | <dd>The system calls this when creating the fragment. Within your implementation, you should |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 166 | initialize essential components of the fragment that you want to retain when the fragment is |
| 167 | paused or stopped, then resumed.</dd> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 168 | <dt>{@link android.app.Fragment#onCreateView onCreateView()}</dt> |
| 169 | <dd>The system calls this when it's time for the fragment to draw its user interface for the |
| 170 | first time. To draw a UI for your fragment, you must return a {@link android.view.View} from this |
| 171 | method that is the root of your fragment's layout. You can return null if the fragment does not |
| 172 | provide a UI.</dd> |
| 173 | <dt>{@link android.app.Activity#onPause onPause()}</dt> |
| 174 | <dd>The system calls this method as the first indication that the user is leaving the |
| 175 | fragment (though it does not always mean the fragment is being destroyed). This is usually where you |
| 176 | should commit any changes that should be persisted beyond the current user session (because |
| 177 | the user might not come back).</dd> |
| 178 | </dl> |
| 179 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 180 | <p>Most applications should implement at least these three methods for every fragment, but there are |
| 181 | several other callback methods you should also use to handle various stages of the |
| 182 | fragment lifecycle. All the lifecycle callback methods are discussed more later, in the section |
| 183 | about <a href="#Lifecycle">Handling the Fragment Lifecycle</a>.</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 184 | |
| 185 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 186 | <p>There are also a few subclasses that you might want to extend, instead of the base {@link |
| 187 | android.app.Fragment} class:</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 188 | |
| 189 | <dl> |
| 190 | <dt>{@link android.app.DialogFragment}</dt> |
| 191 | <dd>Displays a floating dialog. Using this class to create a dialog is a good alternative to using |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 192 | the dialog helper methods in the {@link android.app.Activity} class, because you can |
| 193 | incorporate a fragment dialog into the back stack of fragments managed by the activity, |
| 194 | allowing the user to return to a dismissed fragment.</dd> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 195 | |
| 196 | <dt>{@link android.app.ListFragment}</dt> |
| 197 | <dd>Displays a list of items that are managed by an adapter (such as a {@link |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 198 | android.widget.SimpleCursorAdapter}), similar to {@link android.app.ListActivity}. It provides |
| 199 | several methods for managing a list view, such as the {@link |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 200 | android.app.ListFragment#onListItemClick(ListView,View,int,long) onListItemClick()} callback to |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 201 | handle click events.</dd> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 202 | |
| 203 | <dt>{@link android.preference.PreferenceFragment}</dt> |
| 204 | <dd>Displays a hierarchy of {@link android.preference.Preference} objects as a list, similar to |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 205 | {@link android.preference.PreferenceActivity}. This is useful when creating a "settings" |
| 206 | activity for your application.</dd> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 207 | </dl> |
| 208 | |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 209 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 210 | <h3 id="UI">Adding a user interface</h3> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 211 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 212 | <p>A fragment is usually used as part of an activity's user interface and contributes its own |
| 213 | layout to the activity.</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 214 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 215 | <p>To provide a layout for a fragment, you must implement the {@link |
| 216 | android.app.Fragment#onCreateView onCreateView()} callback method, which the Android system calls |
| 217 | when it's time for the fragment to draw its layout. Your implementation of this method must return a |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 218 | {@link android.view.View} that is the root of your fragment's layout.</p> |
| 219 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 220 | <p class="note"><strong>Note:</strong> If your fragment is a subclass of {@link |
| 221 | android.app.ListFragment}, the default implementation returns a {@link android.widget.ListView} from |
| 222 | {@link android.app.Fragment#onCreateView onCreateView()}, so you don't need to implement it.</p> |
| 223 | |
| 224 | <p>To return a layout from {@link |
| 225 | android.app.Fragment#onCreateView onCreateView()}, you can inflate it from a <a |
| 226 | href="{@docRoot}guide/topics/resources/layout-resource.html">layout resource</a> defined in XML. To |
| 227 | help you do so, {@link android.app.Fragment#onCreateView onCreateView()} provides a |
| 228 | {@link android.view.LayoutInflater} object.</p> |
| 229 | |
| 230 | <p>For example, here's a subclass of {@link android.app.Fragment} that loads a layout from the |
| 231 | {@code example_fragment.xml} file:</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 232 | |
| 233 | <pre> |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 234 | public static class ExampleFragment extends Fragment { |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 235 | @Override |
| 236 | public View onCreateView(LayoutInflater inflater, ViewGroup container, |
| 237 | Bundle savedInstanceState) { |
| 238 | // Inflate the layout for this fragment |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 239 | return inflater.inflate(R.layout.example_fragment, container, false); |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 240 | } |
| 241 | } |
| 242 | </pre> |
| 243 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 244 | <div class="sidebox-wrapper"> |
| 245 | <div class="sidebox"> |
| 246 | <h3>Creating a layout</h3> |
| 247 | <p>In the sample above, {@code R.layout.example_fragment} is a reference to a layout resource |
| 248 | named {@code example_fragment.xml} saved in the application resources. For information about how to |
| 249 | create a layout in XML, see the <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> |
| 250 | documentation.</p> |
| 251 | </div> |
| 252 | </div> |
| 253 | |
| 254 | <p>The {@code container} parameter passed to {@link android.app.Fragment#onCreateView |
| 255 | onCreateView()} is the parent {@link android.view.ViewGroup} (from the activity's layout) in which |
| 256 | your fragment layout |
| 257 | will be inserted. The {@code savedInstanceState} parameter is a {@link android.os.Bundle} that |
| 258 | provides data about the previous instance of the fragment, if the fragment is being resumed |
| 259 | (restoring state is discussed more in the section about <a href="#Lifecycle">Handling the |
| 260 | Fragment Lifecycle</a>).</p> |
| 261 | |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 262 | <p>The {@link android.view.LayoutInflater#inflate(int,ViewGroup,boolean) inflate()} method takes |
| 263 | three arguments:</p> |
| 264 | <ul> |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 265 | <li>The resource ID of the layout you want to inflate.</li> |
| 266 | <li>The {@link android.view.ViewGroup} to be the parent of the inflated layout. Passing the {@code |
| 267 | container} is important in order for the system to apply layout parameters to the root view of the |
| 268 | inflated layout, specified by the parent view in which it's going.</li> |
| 269 | <li>A boolean indicating whether the inflated layout should be attached to the {@link |
| 270 | android.view.ViewGroup} (the second parameter) during inflation. (In this case, this |
| 271 | is false because the system is already inserting the inflated layout into the {@code |
| 272 | container}—passing true would create a redundant view group in the final layout.)</li> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 273 | </ul> |
| 274 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 275 | <p>Now you've seen how to create a fragment that provides a layout. Next, you need to add |
| 276 | the fragment to your activity.</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 277 | |
| 278 | |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 279 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 280 | <h3 id="Adding">Adding a fragment to an activity</h3> |
| 281 | |
| 282 | <p>Usually, a fragment contributes a portion of UI to the host activity, which is embedded as a part |
| 283 | of the activity's overall view hierarchy. There are two ways you can add a fragment to the activity |
| 284 | layout:</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 285 | |
| 286 | <ul> |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 287 | <li><b>Declare the fragment inside the activity's layout file.</b> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 288 | <p>In this case, you can |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 289 | specify layout properties for the fragment as if it were a view. For example, here's the layout |
| 290 | file for an activity with two fragments:</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 291 | <pre> |
| 292 | <?xml version="1.0" encoding="utf-8"?> |
| 293 | <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
| 294 | android:orientation="horizontal" |
| 295 | android:layout_width="match_parent" |
| 296 | android:layout_height="match_parent"> |
| 297 | <fragment android:name="com.example.news.ArticleListFragment" |
| 298 | android:id="@+id/list" |
| 299 | android:layout_weight="1" |
| 300 | android:layout_width="0dp" |
| 301 | android:layout_height="match_parent" /> |
| 302 | <fragment android:name="com.example.news.ArticleReaderFragment" |
| 303 | android:id="@+id/viewer" |
| 304 | android:layout_weight="2" |
| 305 | android:layout_width="0dp" |
| 306 | android:layout_height="match_parent" /> |
| 307 | </LinearLayout> |
| 308 | </pre> |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 309 | <p>The {@code android:name} attribute in the {@code <fragment>} specifies the {@link |
| 310 | android.app.Fragment} class to instantiate in the layout.</p> |
| 311 | |
| 312 | <p>When the system creates this activity layout, it instantiates each fragment specified in the |
| 313 | layout and calls the {@link android.app.Fragment#onCreateView onCreateView()} method for each one, |
| 314 | to retrieve each fragment's layout. The system inserts the {@link android.view.View} returned by the |
| 315 | fragment directly in place of the {@code <fragment>} element.</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 316 | |
| 317 | <div class="note"> |
| 318 | <p><strong>Note:</strong> Each fragment requires a unique identifier that |
| 319 | the system can use to restore the fragment if the activity is restarted (and which you can use to |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 320 | capture the fragment to perform transactions, such as remove it). There are three ways to provide an |
| 321 | ID for a fragment:</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 322 | <ul> |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 323 | <li>Supply the {@code android:id} attribute with a unique ID.</li> |
| 324 | <li>Supply the {@code android:tag} attribute with a unique string.</li> |
| 325 | <li>If you provide neither of the previous two, the system uses the ID of the container |
| 326 | view.</li> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 327 | </ul> |
| 328 | </div> |
| 329 | </li> |
| 330 | |
| 331 | <li><b>Or, programmatically add the fragment to an existing {@link android.view.ViewGroup}.</b> |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 332 | <p>At any time while your activity is running, you can add fragments to your activity layout. You |
| 333 | simply need to specify a {@link |
| 334 | android.view.ViewGroup} in which to place the fragment.</p> |
| 335 | <p>To make fragment transactions in your activity (such as add, remove, or replace a |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 336 | fragment), you must use APIs from {@link android.app.FragmentTransaction}. You can get an instance |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 337 | of {@link android.app.FragmentTransaction} from your {@link android.app.Activity} like this:</p> |
| 338 | |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 339 | <pre> |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 340 | FragmentManager fragmentManager = {@link android.app.Activity#getFragmentManager()} |
Dianne Hackborn | 17b9b81 | 2011-01-17 17:16:02 -0800 | [diff] [blame] | 341 | FragmentTransaction fragmentTransaction = fragmentManager.{@link android.app.FragmentManager#beginTransaction()}; |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 342 | </pre> |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 343 | |
| 344 | <p>You can then add a fragment using the {@link |
| 345 | android.app.FragmentTransaction#add(int,Fragment) add()} method, specifying the fragment to add and |
| 346 | the view in which to insert it. For example:</p> |
| 347 | |
| 348 | <pre> |
| 349 | ExampleFragment fragment = new ExampleFragment(); |
| 350 | fragmentTransaction.add(R.id.fragment_container, fragment); |
| 351 | fragmentTransaction.commit(); |
| 352 | </pre> |
| 353 | |
| 354 | <p>The first argument passed to {@link android.app.FragmentTransaction#add(int,Fragment) add()} |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 355 | is the {@link android.view.ViewGroup} in which the fragment should be placed, specified by |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 356 | resource ID, and the second parameter is the fragment to add.</p> |
| 357 | <p>Once you've made your changes with |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 358 | {@link android.app.FragmentTransaction}, you must |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 359 | call {@link android.app.FragmentTransaction#commit} for the changes to take effect.</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 360 | </li> |
| 361 | </ul> |
| 362 | |
| 363 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 364 | <h4 id="AddingWithoutUI">Adding a fragment without a UI</h4> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 365 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 366 | <p>The examples above show how to add a fragment to your activity in order to provide a UI. However, |
| 367 | you can also use a fragment to provide a background behavior for the activity without presenting |
| 368 | additional UI.</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 369 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 370 | <p>To add a fragment without a UI, add the fragment from the activity using {@link |
| 371 | android.app.FragmentTransaction#add(Fragment,String)} (supplying a unique string "tag" for the |
| 372 | fragment, rather than a view ID). This adds the fragment, but, because it's not associated with a |
| 373 | view in the activity layout, it does not receive a call to {@link |
| 374 | android.app.Fragment#onCreateView onCreateView()}. So you don't need to implement that method.</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 375 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 376 | <p>Supplying a string tag for the fragment isn't strictly for non-UI fragments—you can also |
| 377 | supply string tags to fragments that do have a UI—but if the fragment does not have a |
| 378 | UI, then the string tag is the only way to identify it. If you want to get the fragment from the |
| 379 | activity later, you need to use {@link android.app.FragmentManager#findFragmentByTag |
| 380 | findFragmentByTag()}.</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 381 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 382 | <p>For an example activity that uses a fragment as a background worker, without a UI, see the <a |
| 383 | href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/FragmentRetainInstance.html">{@code |
| 384 | FragmentRetainInstance.java}</a> sample.</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 385 | |
| 386 | |
| 387 | |
| 388 | <h2 id="Managing">Managing Fragments</h2> |
| 389 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 390 | <p>To manage the fragments in your activity, you need to use {@link android.app.FragmentManager}. To |
| 391 | get it, call {@link android.app.Activity#getFragmentManager()} from your activity.</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 392 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 393 | <p>Some things that you can do with {@link android.app.FragmentManager} include:</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 394 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 395 | <ul> |
| 396 | <li>Get fragments that exist in the activity, with {@link |
| 397 | android.app.FragmentManager#findFragmentById findFragmentById()} (for fragments that provide a UI in |
| 398 | the activity layout) or {@link android.app.FragmentManager#findFragmentByTag |
| 399 | findFragmentByTag()} (for fragments that do or don't provide a UI).</li> |
| 400 | <li>Pop fragments off the back stack, with {@link |
| 401 | android.app.FragmentManager#popBackStack()} (simulating a BACK command by the user).</li> |
| 402 | <li>Register a listener for changes to the back stack, with {@link |
| 403 | android.app.FragmentManager#addOnBackStackChangedListener addOnBackStackChangedListener()}.</li> |
| 404 | </ul> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 405 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 406 | <p>For more information about these methods and others, refer to the {@link |
| 407 | android.app.FragmentManager} class documentation.</p> |
| 408 | |
| 409 | <p>As demonstrated in the previous section, you can also use {@link android.app.FragmentManager} |
| 410 | to open a {@link android.app.FragmentTransaction}, which allows you to perform transactions, such as |
| 411 | add and remove fragments.</p> |
| 412 | |
| 413 | |
| 414 | <h2 id="Transactions">Performing Fragment Transactions</h2> |
| 415 | |
| 416 | <p>A great feature about using fragments in your activity is the ability to add, remove, replace, |
| 417 | and perform other actions with them, in response to user interaction. Each set of changes that you |
| 418 | commit to the activity is called a transaction and you can perform one using APIs in {@link |
| 419 | android.app.FragmentTransaction}. You can also save each transaction to a back stack managed by the |
| 420 | activity, allowing the user to navigate backward through the fragment changes (similar to navigating |
| 421 | backward through activities).</p> |
| 422 | |
| 423 | <p>You can acquire an instance of {@link android.app.FragmentTransaction} from the {@link |
| 424 | android.app.FragmentManager} like this:</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 425 | |
| 426 | <pre> |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 427 | FragmentManager fragmentManager = {@link android.app.Activity#getFragmentManager()}; |
Dianne Hackborn | 17b9b81 | 2011-01-17 17:16:02 -0800 | [diff] [blame] | 428 | FragmentTransaction fragmentTransaction = fragmentManager.{@link android.app.FragmentManager#beginTransaction()}; |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 429 | </pre> |
| 430 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 431 | <p>Each transaction is a set of changes that you want to perform at the same time. You can set |
| 432 | up all the changes you want to perform for a given transaction using methods such as {@link |
| 433 | android.app.FragmentTransaction#add add()}, {@link android.app.FragmentTransaction#remove remove()}, |
| 434 | and {@link android.app.FragmentTransaction#replace replace()}. Then, to apply the transaction |
| 435 | to the activity, you must call {@link android.app.FragmentTransaction#commit()}.</p> |
| 436 | </dl> |
| 437 | |
| 438 | <p>Before you call {@link |
| 439 | android.app.FragmentTransaction#commit()}, however, you might want to call {@link |
| 440 | android.app.FragmentTransaction#addToBackStack addToBackStack()}, in order to add the transaction |
| 441 | to a back stack of fragment transactions. This back stack is managed by the activity and allows |
| 442 | the user to return to the previous fragment state, by pressing the BACK key.</p> |
| 443 | |
| 444 | <p>For example, here's how you can replace one fragment with another, and preserve the previous |
| 445 | state in the back stack:</p> |
| 446 | |
| 447 | <pre> |
| 448 | // Create new fragment and transaction |
| 449 | Fragment newFragment = new ExampleFragment(); |
Dianne Hackborn | 17b9b81 | 2011-01-17 17:16:02 -0800 | [diff] [blame] | 450 | FragmentTransaction transaction = getFragmentManager().beginTransaction(); |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 451 | |
| 452 | // Replace whatever is in the fragment_container view with this fragment, |
| 453 | // and add the transaction to the back stack |
| 454 | transaction.replace(R.id.fragment_container, newFragment); |
| 455 | transaction.addToBackStack(null); |
| 456 | |
| 457 | // Commit the transaction |
| 458 | transaction.commit(); |
| 459 | </pre> |
| 460 | |
| 461 | <p>In this example, {@code newFragment} replaces whatever fragment (if any) is currently in the |
| 462 | layout container identified by the {@code R.id.fragment_container} ID. By calling {@link |
| 463 | android.app.FragmentTransaction#addToBackStack addToBackStack()}, the replace transaction is |
| 464 | saved to the back stack so the user can reverse the transaction and bring back the |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 465 | previous fragment by pressing the BACK key.</p> |
| 466 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 467 | <p>If you add multiple changes to the transaction (such as another {@link |
| 468 | android.app.FragmentTransaction#add add()} or {@link android.app.FragmentTransaction#remove |
| 469 | remove()}) and call {@link |
| 470 | android.app.FragmentTransaction#addToBackStack addToBackStack()}, then all changes applied |
| 471 | before you call {@link android.app.FragmentTransaction#commit commit()} are added to the |
| 472 | back stack as a single transaction and the BACK key will reverse them all together.</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 473 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 474 | <p>The order in which you add changes to a {@link android.app.FragmentTransaction} doesn't matter, |
| 475 | except:</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 476 | <ul> |
| 477 | <li>You must call {@link android.app.FragmentTransaction#commit()} last</li> |
| 478 | <li>If you're adding multiple fragments to the same container, then the order in which |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 479 | you add them determines the order they appear in the view hierarchy</li> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 480 | </ul> |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 481 | |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 482 | <p>If you do not call {@link android.app.FragmentTransaction#addToBackStack(String) |
| 483 | addToBackStack()} when you perform a transaction that removes a fragment, then that fragment is |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 484 | destroyed when the transaction is committed and the user cannot navigate back to it. Whereas, if you |
| 485 | do call {@link android.app.FragmentTransaction#addToBackStack(String) addToBackStack()} when |
| 486 | removing a fragment, then the fragment is <em>stopped</em> and will be resumed if the user navigates |
| 487 | back.</p> |
| 488 | |
| 489 | <p class="note"><strong>Tip:</strong> For each fragment transaction, you can apply a transition |
| 490 | animation, by calling {@link android.app.FragmentTransaction#setTransition setTransition()} before |
| 491 | you commit.</p> |
| 492 | |
| 493 | <p>Calling {@link android.app.FragmentTransaction#commit()} does not perform the transaction |
| 494 | immediately. Rather, it schedules it to run on the activity's UI thread (the "main" thread) as soon |
| 495 | as the thread is able to do so. If necessary, however, you may call {@link |
| 496 | android.app.FragmentManager#executePendingTransactions()} from your UI thread to immediately execute |
| 497 | transactions submitted by {@link android.app.FragmentTransaction#commit()}. Doing so is |
| 498 | usually not necessary unless the transaction is a dependency for jobs in other threads.</p> |
| 499 | |
| 500 | <p class="caution"><strong>Caution:</strong> You can commit a transaction using {@link |
| 501 | android.app.FragmentTransaction#commit commit()} only prior to the activity <a |
| 502 | href="{@docRoot}guide/topics/fundamentals/activities.html#SavingActivityState">saving its |
| 503 | state</a> (when the user leaves the activity). If you attempt to commit after that point, an |
| 504 | exception will be thrown. This is because the state after the commit can be lost if the activity |
| 505 | needs to be restored. For situations in which its okay that you lose the commit, use {@link |
| 506 | android.app.FragmentTransaction#commitAllowingStateLoss()}.</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 507 | |
| 508 | |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 509 | |
| 510 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 511 | <h2 id="CommunicatingWithActivity">Communicating with the Activity</h2> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 512 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 513 | <p>Although a {@link android.app.Fragment} is implemented as an object that's independent from an |
| 514 | {@link android.app.Activity} and can be used inside multiple activities, a given instance of |
| 515 | a fragment is directly tied to the activity that contains it.</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 516 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 517 | <p>Specifically, the fragment can access the {@link android.app.Activity} instance with {@link |
| 518 | android.app.Fragment#getActivity()} and easily perform tasks such as find a view in the |
| 519 | activity layout:</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 520 | |
| 521 | <pre> |
| 522 | View listView = {@link android.app.Fragment#getActivity()}.{@link android.app.Activity#findViewById findViewById}(R.id.list); |
| 523 | </pre> |
| 524 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 525 | <p>Likewise, your activity can call methods in the fragment by acquiring a reference to the |
| 526 | {@link android.app.Fragment} from {@link android.app.FragmentManager}, using {@link |
| 527 | android.app.FragmentManager#findFragmentById findFragmentById()} or {@link |
| 528 | android.app.FragmentManager#findFragmentByTag findFragmentByTag()}. For example:</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 529 | |
| 530 | <pre> |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 531 | ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment); |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 532 | </pre> |
| 533 | |
| 534 | |
Scott Main | a90eb8f | 2011-04-05 14:05:03 -0700 | [diff] [blame] | 535 | <h3 id="EventCallbacks">Creating event callbacks to the activity</h3> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 536 | |
| 537 | <p>In some cases, you might need a fragment to share events with the activity. A good way to do that |
| 538 | is to define a callback interface inside the fragment and require that the host activity implement |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 539 | it. When the activity receives a callback through the interface, it can share the information with |
| 540 | other fragments in the layout as necessary.</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 541 | |
| 542 | <p>For example, if a news application has two fragments in an activity—one to show a list of |
| 543 | articles (fragment A) and another to display an article (fragment B)—then fragment A must tell |
| 544 | the activity when a list item is selected so that it can tell fragment B to display the article. In |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 545 | this case, the {@code OnArticleSelectedListener} interface is declared inside fragment A:</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 546 | |
| 547 | <pre> |
| 548 | public static class FragmentA extends ListFragment { |
| 549 | ... |
| 550 | // Container Activity must implement this interface |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 551 | public interface OnArticleSelectedListener { |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 552 | public void onArticleSelected(Uri articleUri); |
| 553 | } |
| 554 | ... |
| 555 | } |
| 556 | </pre> |
| 557 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 558 | <p>Then the activity that hosts the fragment implements the {@code OnArticleSelectedListener} |
| 559 | interface and |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 560 | overrides {@code onArticleSelected()} to notify fragment B of the event from fragment A. To ensure |
| 561 | that the host activity implements this interface, fragment A's {@link |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 562 | android.app.Fragment#onAttach onAttach()} callback method (which the system calls when adding |
| 563 | the fragment to the activity) instantiates an instance of {@code OnArticleSelectedListener} by |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 564 | casting the {@link android.app.Activity} that is passed into {@link android.app.Fragment#onAttach |
| 565 | onAttach()}:</p> |
| 566 | |
| 567 | <pre> |
| 568 | public static class FragmentA extends ListFragment { |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 569 | OnArticleSelectedListener mListener; |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 570 | ... |
| 571 | @Override |
| 572 | public void onAttach(Activity activity) { |
| 573 | super.onAttach(activity); |
| 574 | try { |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 575 | mListener = (OnArticleSelectedListener) activity; |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 576 | } catch (ClassCastException e) { |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 577 | throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener"); |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 578 | } |
| 579 | } |
| 580 | ... |
| 581 | } |
| 582 | </pre> |
| 583 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 584 | <p>If the activity has not implemented the interface, then the fragment throws a |
| 585 | {@link java.lang.ClassCastException}. |
| 586 | On success, the {@code mListener} member holds a reference to activity's implementation of |
| 587 | {@code OnArticleSelectedListener}, so that fragment A can share events with the activity by calling |
| 588 | methods defined by the {@code OnArticleSelectedListener} interface. For example, if fragment A is an |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 589 | extension of {@link android.app.ListFragment}, each time |
| 590 | the user clicks a list item, the system calls {@link android.app.ListFragment#onListItemClick |
| 591 | onListItemClick()} in the fragment, which then calls {@code onArticleSelected()} to share |
| 592 | the event with the activity:</p> |
| 593 | |
| 594 | <pre> |
| 595 | public static class FragmentA extends ListFragment { |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 596 | OnArticleSelectedListener mListener; |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 597 | ... |
| 598 | @Override |
| 599 | public void onListItemClick(ListView l, View v, int position, long id) { |
| 600 | // Append the clicked item's row ID with the content provider Uri |
| 601 | Uri noteUri = ContentUris.{@link android.content.ContentUris#withAppendedId withAppendedId}(ArticleColumns.CONTENT_URI, id); |
| 602 | // Send the event and Uri to the host activity |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 603 | mListener.onArticleSelected(noteUri); |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 604 | } |
| 605 | ... |
| 606 | } |
| 607 | </pre> |
| 608 | |
| 609 | <p>The {@code id} parameter passed to {@link |
| 610 | android.app.ListFragment#onListItemClick onListItemClick()} is the row ID of the clicked item, |
| 611 | which the activity (or other fragment) uses to fetch the article from the application's {@link |
| 612 | android.content.ContentProvider}.</p> |
| 613 | |
| 614 | <p><!--To see a complete implementation of this kind of callback interface, see the <a |
| 615 | href="{@docRoot}resources/samples/NotePad/index.html">NotePad sample</a>. -->More information about |
| 616 | using a content provider is available in the <a |
| 617 | href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a> document.</p> |
| 618 | |
| 619 | |
| 620 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 621 | <h3 id="ActionBar">Adding items to the Action Bar</h3> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 622 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 623 | <p>Your fragments can contribute menu items to the activity's <a |
| 624 | href="{@docRoot}guide/topics/ui/menus.html#options-menu">Options Menu</a> (and, consequently, the <a |
| 625 | href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a>) by implementing |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 626 | {@link android.app.Fragment#onCreateOptionsMenu(Menu,MenuInflater) onCreateOptionsMenu()}. In order |
| 627 | for this method to receive calls, however, you must call {@link |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 628 | android.app.Fragment#setHasOptionsMenu(boolean) setHasOptionsMenu()} during {@link |
| 629 | android.app.Fragment#onCreate(Bundle) onCreate()}, to indicate that the fragment |
| 630 | would like to add items to the Options Menu (otherwise, the fragment will not receive a call to |
| 631 | {@link android.app.Fragment#onCreateOptionsMenu onCreateOptionsMenu()}).</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 632 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 633 | <p>Any items that you then add to the Options Menu from the fragment are appended to the existing |
| 634 | menu items. The fragment also receives callbacks to {@link |
| 635 | android.app.Fragment#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} when a menu item |
| 636 | is selected.</p> |
| 637 | |
| 638 | <p>You can also register a view in your fragment layout to provide a context menu by calling {@link |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 639 | android.app.Fragment#registerForContextMenu(View) registerForContextMenu()}. When the user opens |
| 640 | the context menu, the fragment receives a call to {@link |
| 641 | android.app.Fragment#onCreateContextMenu(ContextMenu,View,ContextMenu.ContextMenuInfo) |
| 642 | onCreateContextMenu()}. When the user selects an item, the fragment receives a call to {@link |
| 643 | android.app.Fragment#onContextItemSelected(MenuItem) onContextItemSelected()}.</p> |
| 644 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 645 | <p class="note"><strong>Note:</strong> Although your fragment receives an on-item-selected callback |
| 646 | for each menu item it adds, the activity is first to receive the respective callback when the user |
| 647 | selects a menu item. If the activity's implementation of the on-item-selected callback does not |
| 648 | handle the selected item, then the event is passed to the fragment's callback. This is true for |
| 649 | the Options Menu and context menus.</p> |
| 650 | |
Scott Main | b10b48f | 2011-09-13 16:40:52 -0700 | [diff] [blame] | 651 | <p>For more information about menus, see the <a |
| 652 | href="{@docRoot}guide/topics/ui/menus.html">Menus</a> and <a |
| 653 | href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> developer guides.</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 654 | |
| 655 | |
| 656 | |
| 657 | |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 658 | <h2 id="Lifecycle">Handling the Fragment Lifecycle</h2> |
| 659 | |
Scott Main | 9c9b9ad | 2011-12-29 11:28:38 -0800 | [diff] [blame] | 660 | <div class="figure" style="width:350px"> |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 661 | <img src="{@docRoot}images/activity_fragment_lifecycle.png" alt=""/> |
| 662 | <p class="img-caption"><strong>Figure 3.</strong> The activity lifecycle's affect on the fragment |
| 663 | lifecycle.</p> |
| 664 | </div> |
| 665 | |
| 666 | <p>Managing the lifecycle of a fragment is a lot like managing the lifecycle of an activity. Like |
| 667 | an activity, a fragment can exist in three states:</p> |
| 668 | |
| 669 | <dl> |
| 670 | <dt><i>Resumed</i></dt> |
| 671 | <dd>The fragment is visible in the running activity.</dd> |
| 672 | |
| 673 | <dt><i>Paused</i></dt> |
| 674 | <dd>Another activity is in the foreground and has focus, but the activity in which this |
| 675 | fragment lives is still visible (the foreground activity is partially transparent or doesn't |
| 676 | cover the entire screen).</dd> |
| 677 | |
| 678 | <dt><i>Stopped</i></dt> |
| 679 | <dd>The fragment is not visible. Either the host activity has been stopped or the |
| 680 | fragment has been removed from the activity but added to the back stack. A stopped fragment is |
| 681 | still alive (all state and member information is retained by the system). However, it is no longer |
| 682 | visible to the user and will be killed if the activity is killed.</dd> |
| 683 | </dl> |
| 684 | |
| 685 | <p>Also like an activity, you can retain the state of a fragment using a {@link |
| 686 | android.os.Bundle}, in case the activity's process is killed and you need to restore the |
| 687 | fragment state when the activity is recreated. You can save the state during the fragment's {@link |
| 688 | android.app.Fragment#onSaveInstanceState onSaveInstanceState()} callback and restore it during |
| 689 | either {@link android.app.Fragment#onCreate onCreate()}, {@link |
| 690 | android.app.Fragment#onCreateView onCreateView()}, or {@link |
| 691 | android.app.Fragment#onActivityCreated onActivityCreated()}. For more information about saving |
| 692 | state, see the <a |
| 693 | href="{@docRoot}guide/topics/fundamentals/activities.html#SavingActivityState">Activities</a> |
| 694 | document.</p> |
| 695 | |
| 696 | <p>The most significant difference in lifecycle between an activity and a fragment is how one is |
| 697 | stored in its respective back stack. An activity is placed into a back stack of activities |
| 698 | that's managed by the system when it's stopped, by default (so that the user can navigate back |
| 699 | to it with the BACK key, as discussed in <a |
| 700 | href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back Stack</a>). |
| 701 | However, a fragment is placed into a back stack managed by the host activity only when you |
| 702 | explicitly request that the instance be saved by calling {@link |
| 703 | android.app.FragmentTransaction#addToBackStack(String) addToBackStack()} during a transaction that |
| 704 | removes the fragment.</p> |
| 705 | |
| 706 | <p>Otherwise, managing the fragment lifecycle is very similar to managing the activity |
| 707 | lifecycle. So, the same practices for <a |
| 708 | href="{@docRoot}guide/topics/fundamentals/activities.html#Lifecycle">managing the activity |
| 709 | lifecycle</a> also apply to fragments. What you also need to understand, though, is how the life |
| 710 | of the activity affects the life of the fragment.</p> |
| 711 | |
| 712 | |
| 713 | <h3 id="CoordinatingWithActivity">Coordinating with the activity lifecycle</h3> |
| 714 | |
| 715 | <p>The lifecycle of the activity in which the fragment lives directly affects the lifecycle of the |
| 716 | fragment, such that each lifecycle callback for the activity results in a similar callback for each |
| 717 | fragment. For example, when the activity receives {@link android.app.Activity#onPause}, each |
| 718 | fragment in the activity receives {@link android.app.Fragment#onPause}.</p> |
| 719 | |
| 720 | <p>Fragments have a few extra lifecycle callbacks, however, that handle unique interaction with the |
| 721 | activity in order to perform actions such as build and destroy the fragment's UI. These additional |
| 722 | callback methods are:</p> |
| 723 | |
| 724 | <dl> |
| 725 | <dt>{@link android.app.Fragment#onAttach onAttach()}</dt> |
| 726 | <dd>Called when the fragment has been associated with the activity (the {@link |
| 727 | android.app.Activity} is passed in here).</dd> |
| 728 | <dt>{@link android.app.Fragment#onCreateView onCreateView()}</dt> |
| 729 | <dd>Called to create the view hierarchy associated with the fragment.</dd> |
| 730 | <dt>{@link android.app.Fragment#onActivityCreated onActivityCreated()}</dt> |
| 731 | <dd>Called when the activity's {@link android.app.Activity#onCreate |
| 732 | onCreate()} method has returned.</dd> |
| 733 | <dt>{@link android.app.Fragment#onDestroyView onDestroyView()}</dt> |
| 734 | <dd>Called when the view hierarchy associated with the fragment is being removed.</dd> |
| 735 | <dt>{@link android.app.Fragment#onDetach onDetach()}</dt> |
| 736 | <dd>Called when the fragment is being disassociated from the activity.</dd> |
| 737 | </dl> |
| 738 | |
| 739 | <p>The flow of a fragment's lifecycle, as it is affected by its host activity, is illustrated |
| 740 | by figure 3. In this figure, you can see how each successive state of the activity determines which |
| 741 | callback methods a fragment may receive. For example, when the activity has received its {@link |
| 742 | android.app.Activity#onCreate onCreate()} callback, a fragment in the activity receives no more than |
| 743 | the {@link android.app.Fragment#onActivityCreated onActivityCreated()} callback.</p> |
| 744 | |
| 745 | <p>Once the activity reaches the resumed state, you can freely add and remove fragments to the |
| 746 | activity. Thus, only while the activity is in the resumed state can the lifecycle of a fragment |
| 747 | change independently.</p> |
| 748 | |
| 749 | <p>However, when the activity leaves the resumed state, the fragment again is pushed through its |
| 750 | lifecycle by the activity.</p> |
| 751 | |
| 752 | |
| 753 | |
| 754 | |
| 755 | <h2 id="Example">Example</h2> |
| 756 | |
| 757 | <p>To bring everything discussed in this document together, here's an example of an activity |
| 758 | using two fragments to create a two-pane layout. The activity below includes one fragment to |
| 759 | show a list of Shakespeare play titles and another to show a summary of the play when selected |
| 760 | from the list. It also demonstrates how to provide different configurations of the fragments, |
| 761 | based on the screen configuration.</p> |
| 762 | |
| 763 | <p class="note"><strong>Note:</strong> The complete source code for this activity is available in |
Scott Main | 13033ea | 2011-02-15 13:18:30 -0800 | [diff] [blame] | 764 | <a |
| 765 | href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.html">{@code |
Scott Main | 04d0e3d | 2011-01-14 15:20:32 -0800 | [diff] [blame] | 766 | FragmentLayout.java}</a>.</p> |
| 767 | |
| 768 | <p>The main activity applies a layout in the usual way, during {@link |
| 769 | android.app.Activity#onCreate onCreate()}:</p> |
| 770 | |
| 771 | {@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java main} |
| 772 | |
| 773 | <p>The layout applied is {@code fragment_layout.xml}:</p> |
| 774 | |
| 775 | {@sample development/samples/ApiDemos/res/layout-land/fragment_layout.xml layout} |
| 776 | |
| 777 | <p>Using this layout, the system instantiates the {@code TitlesFragment} (which lists the play |
| 778 | titles) as soon as the activity loads the layout, while the {@link android.widget.FrameLayout} |
| 779 | (where the fragment for showing the play summary will go) consumes space on the right side of the |
| 780 | screen, but remains empty at first. As you'll see below, it's not until the user selects an item |
| 781 | from the list that a fragment is placed into the {@link android.widget.FrameLayout}.</p> |
| 782 | |
| 783 | <p>However, not all screen configurations are wide enough to show both the list of |
| 784 | plays and the summary, side by side. So, the layout above is used only for the landscape |
| 785 | screen configuration, by saving it at {@code res/layout-land/fragment_layout.xml}.</p> |
| 786 | |
| 787 | <p>Thus, when the screen is in portrait orientation, the system applies the following layout, which |
| 788 | is saved at {@code res/layout/fragment_layout.xml}:</p> |
| 789 | |
| 790 | {@sample development/samples/ApiDemos/res/layout/fragment_layout.xml layout} |
| 791 | |
| 792 | <p>This layout includes only {@code TitlesFragment}. This means that, when the device is in |
| 793 | portrait orientation, only the list of play titles is visible. So, when the user clicks a list |
| 794 | item in this configuration, the application will start a new activity to show the summary, |
| 795 | instead of loading a second fragment.</p> |
| 796 | |
| 797 | <p>Next, you can see how this is accomplished in the fragment classes. First is {@code |
| 798 | TitlesFragment}, which shows the list of Shakespeare play titles. This fragment extends {@link |
| 799 | android.app.ListFragment} and relies on it to handle most of the list view work.</p> |
| 800 | |
| 801 | <p>As you inspect this code, notice that there are two possible behaviors when the user clicks a |
| 802 | list item: depending on which of the two layouts is active, it can either create and display a new |
| 803 | fragment to show the details in the same activity (adding the fragment to the {@link |
| 804 | android.widget.FrameLayout}), or start a new activity (where the fragment can be shown).</p> |
| 805 | |
| 806 | {@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java titles} |
| 807 | |
| 808 | <p>The second fragment, {@code DetailsFragment} shows the play summary for the item selected from |
| 809 | the list from {@code TitlesFragment}:</p> |
| 810 | |
| 811 | {@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java details} |
| 812 | |
| 813 | <p>Recall from the {@code TitlesFragment} class, that, if the user clicks a list item and the |
| 814 | current layout does <em>not</em> include the {@code R.id.details} view (which is where the |
| 815 | {@code DetailsFragment} belongs), then the application starts the {@code DetailsActivity} |
| 816 | activity to display the content of the item.</p> |
| 817 | |
| 818 | <p>Here is the {@code DetailsActivity}, which simply embeds the {@code DetailsFragment} to display |
| 819 | the selected play summary when the screen is in portrait orientation:</p> |
| 820 | |
| 821 | {@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java |
| 822 | details_activity} |
| 823 | |
| 824 | <p>Notice that this activity finishes itself if the configuration is landscape, so that the main |
| 825 | activity can take over and display the {@code DetailsFragment} alongside the {@code TitlesFragment}. |
| 826 | This can happen if the user begins the {@code DetailsActivity} while in portrait orientation, but |
| 827 | then rotates to landscape (which restarts the current activity).</p> |
| 828 | |
| 829 | |
| 830 | <p>For more samples using fragments (and complete source files for this example), |
| 831 | see the sample code available in <a |
| 832 | href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/index.html#Fragment"> |
| 833 | ApiDemos</a> (available for download from the <a |
| 834 | href="{@docRoot}resources/samples/get.html">Samples SDK component</a>).</p> |
Scott Main | c18b534 | 2010-08-17 11:48:09 -0700 | [diff] [blame] | 835 | |
| 836 | |