Fragments
In this document 本文内容
- Design Philosophy 设计理念
- Creating a Fragment 创建一个 fragment
- Managing Fragments
- Performing Fragment Transactions
- Communicating with the Activity
- Handling the Fragment Lifecycle
- Example
Key classes
See also
A Fragment
represents a behavior or a portion of user interface in an Activity
. You can combine multiple fragments in a single activity to build a multi-pane UI and reuse a fragment in multiple activities. You can think of a fragment as a modular section of an activity, which has its own lifecycle, receives its own input events, and which you can add or remove while the activity is running (sort of like a "sub activity" that you can reuse in different activities).
一个 fragment 代表用户界面的某一部分或者某个特性。你可以在单个的 activity 混合使用多个 fragment 来构建一个格子状的用户界面(multi-pane UI),或者,也可以在多个 activity 中重复使用同一个 fragment。你可以将 fragment 理解为是 activity 的一个模块化的部分,它有着自己的生命周期,能够接收它自己的输入事件,并且你可以在 activity 运行过程中,新增或删除它(听上去有点像是一个能够在不同的 activity 中重复使用的“子 activity”)。
A fragment must always be embedded in an activity and the fragment's lifecycle is directly affected by the host activity's lifecycle. For example, when the activity is paused, so are all fragments in it, and when the activity is destroyed, so are all fragments. However, while an activity is running (it is in the resumed lifecycle state), you can manipulate each fragment independently, such as add or remove them. When you perform such a fragment transaction, you can also add it to a back stack that's managed by the activity—each back stack entry in the activity is a record of the fragment transaction that occurred. The back stack allows the user to reverse a fragment transaction (navigate backwards), by pressing the Back button.
一个 fragment 必须嵌入在一个 activity 之中,并且 activity 的生命周期状态会直接影响到内嵌在其中的所有 fragment 生命周期状态。比如,当 activity 暂停时,它里面所有的 fragment 也一样被暂停;当这个 activity 被销毁时,那么它里面的所有 fragment 也跟着被一起销毁。但是,当一个 activity 正在运行的话(即处于生命周期的“继续(resumed)”状态),你就可以分开地控制各个 fragment,比如新增或者移除它们。当你做了一个类似的 fragment 切换操作的同时,你也可以将它添加到一个后台堆栈中,这个后台堆栈是被 activity 所管理着的——后台堆栈中的每个实体都是发生过的 fragment 切换操作的一条记录信息。这个后台堆栈允许用户通过按“返回”按钮来撤销 fragment 切换操作(即向前导航)。
When you add a fragment as a part of your activity layout, it lives in aViewGroup
inside the activity's view hierarchy and the fragment defines its own view layout. You can insert a fragment into your activity layout by declaring the fragment in the activity's layout file, as a <fragment>
element, or from your application code by adding it to an existing ViewGroup
. However, a fragment is not required to be a part of the activity layout; you may also use a fragment without its own UI as an invisible worker for the activity.
当你在你的 activity 布局中新增一个 fragment 时,你需要将它加在一个位于该 activity 的视图阶层中的 ViewGroup 之中,而这个 fragment 会自己定义自己的视图布局。你可以在你的 activity 的布局文件中用 <fragment> 元素来声明一个 fragment ,以将它插入到这个 activity 布局中去,也可以在你应用程序代码中将它添加进已有的 ViewGroup 中。但是,一个 fragment 并非强制需要成为 activity 布局的一部分,你也可以在 activity 中使用一个不带有自己的用户界面的 fragment ,就像一个看不见的工作者一样。
This document describes how to build your application to use fragments, including how fragments can maintain their state when added to the activity's back stack, share events with the activity and other fragments in the activity, contribute to the activity's action bar, and more.
本文介绍了如何使用 fragment 来构建你的应用程序,主要内容有:当 fragment 被添加到 activity 的后台堆栈中时,它们是如何管理自身的状态的;在 activity 中,fragment 是如何与 activity 以及其他 fragment 一起应对各种各样的事件;如何影响到 activity 的动作栏,等等。
Design Philosophy 设计理念
Android introduced fragments in Android 3.0 (API level 11), primarily to support more dynamic and flexible UI designs on large screens, such as tablets. Because a tablet's screen is much larger than that of a handset, there's more room to combine and interchange UI components. Fragments allow such designs without the need for you to manage complex changes to the view hierarchy. By dividing the layout of an activity into fragments, you become able to modify the activity's appearance at runtime and preserve those changes in a back stack that's managed by the activity.
Android 在 3.0 的时候引入了 fragment,目的是为了给大屏设备提供更动态、更灵活的 UI 设计,比如平板电脑。因为平板比手机有着大得多的屏幕,所以也就有了更大的空间来组合或交换 UI 组件。Fragment 的出现满足了这种设计需求,你可以通过它来管理视图层复杂的变化而不用亲力亲为。通过将一个 activity 的布局拆分到多个 fragment 中,你就可以在程序运行时动态地改变 activity 的展现形式并且能在一个由 activity 管理着的后台堆栈中保存这些改变。
For example, a news application can use one fragment to show a list of articles on the left and another fragment to display an article on the right—both fragments appear in one activity, side by side, and each fragment has its own set of lifecycle callback methods and handle their own user input events. Thus, instead of using one activity to select an article and another activity to read the article, the user can select an article and read it all within the same activity, as illustrated in the tablet layout in figure 1.
比如说,一个新的应用程序可以使用一个 fragment 在屏幕左边列出所有文章,然后使用另一个 fragment 在右边显示单篇文章的详细内容——而这两个 fragment 是放在同一个 activity 中并排显示的,并且各自有一套自己的生命周期回调函数,也各自处理各自的输入事件。因此,相对于以往在一个 activity 中选择一篇文章,然后在另一个 activity 中阅读这篇文章的做法,用户现在可以在同一个 activity 中选择一篇文章并阅读它,就像图一中平板的布局那样。
You should design each fragment as a modular and reusable activity component. That is, because each fragment defines its own layout and its own behavior with its own lifecycle callbacks, you can include one fragment in multiple activities, so you should design for reuse and avoid directly manipulating one fragment from another fragment. This is especially important because a modular fragment allows you to change your fragment combinations for different screen sizes. When designing your application to support both tablets and handsets, you can reuse your fragments in different layout configurations to optimize the user experience based on the available screen space. For example, on a handset, it might be necessary to separate fragments to provide a single-pane UI when more than one cannot fit within the same activity.
你应该尽可能地将每一个 fragment 都设计成一个模块化的、可复用的 activity 组件。因为每一个 fragment 都定义了自己的布局并通过自己的生命周期函数定义了自己的行为特性,所以你可以在多个 activity 中重复使用同一个 fragment,也因此,你应该将 fragment 设计成可复用的,避免直接在一个 fragment 中操控另一 fragment。当你将你的应用程序设计成支持同时支持平板以及手持设备时,你就根据可用的屏幕空间大小在不用的布局配置中复用你的 fragment 以优化用户体验。比如,在手持设备中,如果多个 fragment 无法在同一个 activity 中互相适应,那么就有必要分离 fragment 以提供一个单面板的 UI。

Figure 1. An example of how two UI modules defined by fragments can be combined into one activity for a tablet design, but separated for a handset design.
图1.一个示例,展示了在平板中,两个由不同的 fragment 定义的 UI 模块是如何被组合进一个 activity 的,而后又是如何在手持设备中被分离开来。
For example—to continue with the news application example—the application can embed two fragments in Activity A, when running on a tablet-sized device. However, on a handset-sized screen, there's not enough room for both fragments, so Activity A includes only the fragment for the list of articles, and when the user selects an article, it starts Activity B, which includes the second fragment to read the article. Thus, the application supports both tablets and handsets by reusing fragments in different combinations, as illustrated in figure 1.
比如——继续刚才那个新的应用程序的例子——当这个应用程序运行在平板大小的设备上时,它就能够在 Activity A 中嵌入两个 fragment。但当它运行在手机大小的设备上时,就没有那么多的空间同时显示两个 fragment,所以 Activity A 仅包含展示文章列表的 fragment,当用户选择了一篇文章的时候,它就会启动 Activity B,而这个 Activity B 则包含了另一个显示着待阅读的文章的 fragment。因此,这个新的应用程序通过以不同的方式组合、复用 fragment,就像图 1 所示,就能够同时支持平板和手机了。
For more information about designing your application with different fragment combinations for different screen configurations, see the guide to Supporting Tablets and Handsets.
更多有关如何用不同的 fragment 组合来设计你的应用程序以适配不同的屏幕类型,请阅读《Supporting Tablets and Handsets》。
Creating a Fragment 创建一个 fragment

Figure 2. The lifecycle of a fragment (while its activity is running).
To create a fragment, you must create a subclass of Fragment
(or an existing subclass of it). The Fragment
class has code that looks a lot like an Activity
. It contains callback methods similar to an activity, such as onCreate()
, onStart()
, onPause()
, and onStop()
. In fact, if you're converting an existing Android application to use fragments, you might simply move code from your activity's callback methods into the respective callback methods of your fragment.
要创建一个 fragment,你就必须继承 Fragment 类(或者一个已有的 Fragment 的子类)。Fragment 类有着类似于 Activity 的代码,与 Activity 相似的回调方法,比如 onCreate(), onStart(), onPause(),以及 onStop()。事实上,如果你正在将一个已有的 Android 应用改写成使用 fragment 的应用的话,你需要做的可能仅仅是简单地将 Activity 回调方法中的内容拆分到各个 fragment 的回调方法中去就行了。
Usually, you should implement at least the following lifecycle methods:
通常情况下,你最少也应该实现下面这些生命周期方法:
- The system calls this when creating the fragment. Within your implementation, you should initialize essential components of the fragment that you want to retain when the fragment is paused or stopped, then resumed.
- 当创建 fragment 时,系统就会调用这个方法。在你的具体实现过程中,你应该初始化 fragment 所必须的组件,当 fragment 被暂停或者停止时,这些组件会保留,随后被恢复。
-
The system calls this when it's time for the fragment to draw its user interface for the first time. To draw a UI for your fragment, you must return a
View
from this method that is the root of your fragment's layout. You can return null if the fragment does not provide a UI. - 当 fragment 第一次绘制它测用户界面时,系统会为它调用这个方法。想要为你的 fragment 绘制一个 UI,那么你就必须从这个方法中返回一个表示你的 fragment 布局 root(the root of your fragment's layout) 的 View 类对象。如果你的 fragment 并不提供一个 UI 的话,那你就可以直接返回 null。
- The system calls this method as the first indication that the user is leaving the fragment (though it does not always mean the fragment is being destroyed). This is usually where you should commit any changes that should be persisted beyond the current user session (because the user might not come back).
- 系统对这个方法的调用即为用户将要离开你的 fragment 的初始信号(尽管这并不意味着这个 fragment 即将被销毁)。这也是通常情况下你应该保存那些即使当前回话结束也应该被保存的信息的时候(因为用户可以就这么一去不复返了~~~)。
onCreate()
onCreateView()
onPause()
Most applications should implement at least these three methods for every fragment, but there are several other callback methods you should also use to handle various stages of the fragment lifecycle. All the lifecycle callback methods are discussed in more detail in the section about Handling the Fragment Lifecycle.
大多数应用程序应该为每个 fragment 都实现上述三个方法,然还有许多其他的回调方法可以供你实现来对应 fragment 生命周期的各个状态(的变化)。所有的生命周期回调方法都会在“Handing the Fragment Lifecycle”章节中详细介绍。
There are also a few subclasses that you might want to extend, instead of the base Fragment
class:
这还有许多已有的 Fragment 类的子类来供你继承:
-
Displays a floating dialog. Using this class to create a dialog is a good alternative to using the dialog helper methods in the
Activity
class, because you can incorporate a fragment dialog into the back stack of fragments managed by the activity, allowing the user to return to a dismissed fragment. - 一个浮动的对话框。以往的做法是使用 Activity 类的对话框助手方法来实现一个对话框,而现在, 使用这个类来创建一个对话框的做法是一种更好的替代方案,因为你可以将一个 fragment 对话框合并到后台堆栈中(这个堆栈为 activity 所管理)并允许用户返回到一个已被摈弃的 fragment。
-
Displays a list of items that are managed by an adapter (such as a
SimpleCursorAdapter
), similar toListActivity
. It provides several methods for managing a list view, such as theonListItemClick()
callback to handle click events. - 显示一个列表,列表中的内容被一个适配器所管理(比如一个 SimpleCursorAdapter 实例),这有点类似于 ListActivity。它提供了几个管理视图列表的方法,比如可以用来处理单击事件的 onListItemClick() 回调方法
-
Displays a hierarchy of
Preference
objects as a list, similar toPreferenceActivity
. This is useful when creating a "settings" activity for your application. - 将一个 Perference 对象显示成一个列表,这有点类似于 PreferenceActivity。当你为你的应用程序创建一个 “设置” activity 时,这会很有用。
DialogFragment
ListFragment
PreferenceFragment
Adding a user interface 增加一个用户界面
A fragment is usually used as part of an activity's user interface and contributes its own layout to the activity.
一个 fragment 通常的用法是用来构建一个 activity 的部分用户界面,将自己的布局嵌入到 activity 中。
To provide a layout for a fragment, you must implement the onCreateView()
callback method, which the Android system calls when it's time for the fragment to draw its layout. Your implementation of this method must return a View
that is the root of your fragment's layout.
要为 fragment 提供布局的话,你就必须实现 onCreateView() 这个回调方法。在 fragment 绘制它的布局的时候, Android 系统会调用它。你对这个方法的实现的最后必须要返回一个 View 对象,而这个 View 对象必须是代表着你的 fragment 的根布局的 View 对象。
Note: If your fragment is a subclass of ListFragment
, the default implementation returns a ListView
from onCreateView()
, so you don't need to implement it.
注意:如果你的 fragment 是 ListFragment 类的子类,那么 onCreateView() 的默认实现会返回一个 ListView ,因此你不需要再去实现它了。
To return a layout from onCreateView()
, you can inflate it from a layout resource defined in XML. To help you do so, onCreateView()
provides a LayoutInflater
object.
为了能从 onCreateView() 中返回一个布局,你可以通过在 XML 文件中定义的一个布局资源来填充它。为了帮助你完成这一步骤,onCreateView() 提供了一个 LayoutInflater 对象。
For example, here's a subclass of Fragment
that loads a layout from the example_fragment.xml
file:
举个栗子,这是个 Fragment 类的子类,它从 example_fragment.xml 文件中中加载布局:
public static class ExampleFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment return inflater.inflate(R.layout.example_fragment, container, false); } }
Creating a layout 创建一个布局
In the sample above,R.layout.example_fragment
is a reference to a layout resource named example_fragment.xml
saved in the application resources. For information about how to create a layout in XML, see the User Interface documentation.
在上一个示例中, R.layout.example_fragment 是一个保存在应用程序资源中的布局资源文件 example_fragment.xml 的引用。有关如何用XML来创建一个布局的详细内容,请参阅《User Interface》一文。
The container
parameter passed to onCreateView()
is the parent ViewGroup
(from the activity's layout) in which your fragment layout will be inserted. The savedInstanceState
parameter is a Bundle
that provides data about the previous instance of the fragment, if the fragment is being resumed (restoring state is discussed more in the section about Handling the Fragment Lifecycle).
传给 onCreateView() 方法的 containwer 参数就是你 fragment 要插入的父 ViewGroup 对象(来自于 activity 布局)。savedInstanceState 参数是一个 Bundle 对象,如果这个 fragment 正要被继续的话(有关状态恢复的知识,在“Handling the Fragment Lifecycle” 章节有更详细的介绍),它就会提供上一个 fragment 实例保存下来的数据。
The inflate()
method takes three arguments: inflate() 方法需要三个参数:
- The resource ID of the layout you want to inflate. 你想要填充的布局资源 ID
- The
ViewGroup
to be the parent of the inflated layout. Passing thecontainer
is important in order for the system to apply layout parameters to the root view of the inflated layout, specified by the parent view in which it's going. - 被插入的布局的父对象,类型为 ViewGroup。将 container 传递到这是非常重要的,这样系统才能将布局参数应用到被填充的布局的父级上,而这就指定了该 fragment 将要被插入的父级视图。
- A boolean indicating whether the inflated layout should be attached to the
ViewGroup
(the second parameter) during inflation. (In this case, this is false because the system is already inserting the inflated layout into thecontainer
—passing true would create a redundant view group in the final layout.) - 一个布尔值,表明在inflate期间被infalte的布局是否应该附上ViewGroup(第二个参数)。(在这个例子中传入的是false,因为系统已经将被inflate的布局插入到容器中(container)——传入true会在最终的布局里创建一个多余的ViewGroup。)
Now you've seen how to create a fragment that provides a layout. Next, you need to add the fragment to your activity.
现在你已经知道了如何创建一个有布局的fragment。下一步,则需要将fragment添加到activity中。
Adding a fragment to an activity 将fragment添加到activity之中
Usually, a fragment contributes a portion of UI to the host activity, which is embedded as a part of the activity's overall view hierarchy. There are two ways you can add a fragment to the activity layout:
通常,fragment构建了其宿主activity的部分界面,它被被嵌入进 activity 并成为为 activity 整体视图层次的一部分。在 activity 布局中添加 fragment 有两种方法:
- Declare the fragment inside the activity's layout file. 在 activity 布局文件中声明这个 fragment
In this case, you can specify layout properties for the fragment as if it were a view. For example, here's the layout file for an activity with two fragments: 这种方法允许你像定义一个 view 一样来定义 fragment 的布局参数。如果一个 activity 带有 2 个 fragment 就可以像下面这样来配置。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:name="com.example.news.ArticleListFragment" android:id="@+id/list" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" /> <fragment android:name="com.example.news.ArticleReaderFragment" android:id="@+id/viewer" android:layout_weight="2" android:layout_width="0dp" android:layout_height="match_parent" /> </LinearLayout>
The
android:name
attribute in the<fragment>
specifies theFragment
class to instantiate in the layout. <fragment> 标签的 android:name 属性指定了在布局中被实例化的 Fragment 类。When the system creates this activity layout, it instantiates each fragment specified in the layout and calls the
onCreateView()
method for each one, to retrieve each fragment's layout. The system inserts theView
returned by the fragment directly in place of the<fragment>
element. 当系统创建 activity 布局时,它会调用布局中的每个 fragment 的 onCreateView() 方法来实例化每个 fragment ,以获取每个 fragment 的布局。系统会直接在 <fragment> 标签的所在位置插入 onCreateView() 返回的 View 对象。Note: Each fragment requires a unique identifier that the system can use to restore the fragment if the activity is restarted (and which you can use to capture the fragment to perform transactions, such as remove it). There are three ways to provide an ID for a fragment: 注意:每个 fragment 都需要一个唯一的ID以供系统在恢复 fragment 的时候(当activity 被重启的时候,而这个时候也是你能够获得该 fragment 对象并执行状态转换操作的时候)使用。
- Supply the
android:id
attribute with a unique ID. 为 android:id 属性提供一个唯一的 ID 号 - Supply the
android:tag
attribute with a unique string. 为 android:tag 属性提供一个唯一的文字信息 - If you provide neither of the previous two, the system uses the ID of the container view. 如果你上面两个属性都没有设置,那么系统就会使用容器视图的 ID 号
- Supply the
- Or, programmatically add the fragment to an existing
ViewGroup
. 直接使用代码来在一个已有的 ViewGroup 中添加 fragmentAt any time while your activity is running, you can add fragments to your activity layout. You simply need to specify a
ViewGroup
in which to place the fragment. 在activity运行过程中的任何时刻你就可以在你的 activity 布局中新增一个 fragment。你可以简单地只指定一个 ViewGroup,来放置你要添加的 fragment。To make fragment transactions in your activity (such as add, remove, or replace a fragment), you must use APIs from
FragmentTransaction
. You can get an instance ofFragmentTransaction
from yourActivity
like this: 要在 activity 中完成 fragment 的交换过程(比如新增、移除或者替换一个 fragment),你就必须使用 FragmentTransaction 的 API。你可以像下面这样来获取 FragmentTransaction 实例。FragmentManager fragmentManager =
getFragmentManager()
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction()
;You can then add a fragment using the
add()
method, specifying the fragment to add and the view in which to insert it. For example: 你可以使用 add() 方法来新增一个 fragment,指定要新增的 fragment 以及要插入的位置。就像下面代码所示这样:ExampleFragment fragment = new ExampleFragment(); fragmentTransaction.add(R.id.fragment_container, fragment); fragmentTransaction.commit();
The first argument passed to
add()
is theViewGroup
in which the fragment should be placed, specified by resource ID, and the second parameter is the fragment to add.Once you've made your changes with
FragmentTransaction
, you must callcommit()
for the changes to take effect. add() 方法接收的第一个参数就是 fragment 要被放置的 ViewGroup 对象,这个ViewGroup 对象使用资源ID来展示,而第二个参数就是要被新增的 fragment。你必须调用 commit() 方法来提交这个新增操作,不然它就不会有效果。
Adding a fragment without a UI
The examples above show how to add a fragment to your activity in order to provide a UI. However, you can also use a fragment to provide a background behavior for the activity without presenting additional UI.
To add a fragment without a UI, add the fragment from the activity using add(Fragment, String)
(supplying a unique string "tag" for the fragment, rather than a view ID). This adds the fragment, but, because it's not associated with a view in the activity layout, it does not receive a call to onCreateView()
. So you don't need to implement that method.
Supplying a string tag for the fragment isn't strictly for non-UI fragments—you can also supply string tags to fragments that do have a UI—but if the fragment does not have a UI, then the string tag is the only way to identify it. If you want to get the fragment from the activity later, you need to use findFragmentByTag()
.
For an example activity that uses a fragment as a background worker, without a UI, see theFragmentRetainInstance.java
sample, which is included in the SDK samples (available through the Android SDK Manager) and located on your system as<sdk_root>/APIDemos/app/src/main/java/com/example/android/apis/app/FragmentRetainInstance.java
.
Managing Fragments
To manage the fragments in your activity, you need to use FragmentManager
. To get it, callgetFragmentManager()
from your activity.
Some things that you can do with FragmentManager
include:
- Get fragments that exist in the activity, with
findFragmentById()
(for fragments that provide a UI in the activity layout) orfindFragmentByTag()
(for fragments that do or don't provide a UI). - Pop fragments off the back stack, with
popBackStack()
(simulating a Back command by the user). - Register a listener for changes to the back stack, with
addOnBackStackChangedListener()
.
For more information about these methods and others, refer to the FragmentManager
class documentation.
As demonstrated in the previous section, you can also use FragmentManager
to open a FragmentTransaction
, which allows you to perform transactions, such as add and remove fragments.
Performing Fragment Transactions
A great feature about using fragments in your activity is the ability to add, remove, replace, and perform other actions with them, in response to user interaction. Each set of changes that you commit to the activity is called a transaction and you can perform one using APIs in FragmentTransaction
. You can also save each transaction to a back stack managed by the activity, allowing the user to navigate backward through the fragment changes (similar to navigating backward through activities).
You can acquire an instance of FragmentTransaction
from the FragmentManager
like this:
FragmentManager fragmentManager =getFragmentManager()
; FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction()
;
Each transaction is a set of changes that you want to perform at the same time. You can set up all the changes you want to perform for a given transaction using methods such as add()
, remove()
, and replace()
. Then, to apply the transaction to the activity, you must call commit()
.
Before you call commit()
, however, you might want to call addToBackStack()
, in order to add the transaction to a back stack of fragment transactions. This back stack is managed by the activity and allows the user to return to the previous fragment state, by pressing the Back button.
For example, here's how you can replace one fragment with another, and preserve the previous state in the back stack:
// Create new fragment and transaction Fragment newFragment = new ExampleFragment(); FragmentTransaction transaction = getFragmentManager().beginTransaction(); // Replace whatever is in the fragment_container view with this fragment, // and add the transaction to the back stack transaction.replace(R.id.fragment_container, newFragment); transaction.addToBackStack(null); // Commit the transaction transaction.commit();
In this example, newFragment
replaces whatever fragment (if any) is currently in the layout container identified by the R.id.fragment_container
ID. By calling addToBackStack()
, the replace transaction is saved to the back stack so the user can reverse the transaction and bring back the previous fragment by pressing the Backbutton.
If you add multiple changes to the transaction (such as another add()
or remove()
) and calladdToBackStack()
, then all changes applied before you call commit()
are added to the back stack as a single transaction and the Back button will reverse them all together.
The order in which you add changes to a FragmentTransaction
doesn't matter, except:
- You must call
commit()
last - If you're adding multiple fragments to the same container, then the order in which you add them determines the order they appear in the view hierarchy
If you do not call addToBackStack()
when you perform a transaction that removes a fragment, then that fragment is destroyed when the transaction is committed and the user cannot navigate back to it. Whereas, if you do call addToBackStack()
when removing a fragment, then the fragment is stopped and will be resumed if the user navigates back.
Tip: For each fragment transaction, you can apply a transition animation, by calling setTransition()
before you commit.
Calling commit()
does not perform the transaction immediately. Rather, it schedules it to run on the activity's UI thread (the "main" thread) as soon as the thread is able to do so. If necessary, however, you may callexecutePendingTransactions()
from your UI thread to immediately execute transactions submitted bycommit()
. Doing so is usually not necessary unless the transaction is a dependency for jobs in other threads.
Caution: You can commit a transaction using commit()
only prior to the activity saving its state (when the user leaves the activity). If you attempt to commit after that point, an exception will be thrown. This is because the state after the commit can be lost if the activity needs to be restored. For situations in which its okay that you lose the commit, use commitAllowingStateLoss()
.
Communicating with the Activity
Although a Fragment
is implemented as an object that's independent from an Activity
and can be used inside multiple activities, a given instance of a fragment is directly tied to the activity that contains it.
Specifically, the fragment can access the Activity
instance with getActivity()
and easily perform tasks such as find a view in the activity layout:
View listView =getActivity()
.findViewById
(R.id.list);
Likewise, your activity can call methods in the fragment by acquiring a reference to the Fragment
fromFragmentManager
, using findFragmentById()
or findFragmentByTag()
. For example:
ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);
Creating event callbacks to the activity
In some cases, you might need a fragment to share events with the activity. A good way to do that is to define a callback interface inside the fragment and require that the host activity implement it. When the activity receives a callback through the interface, it can share the information with other fragments in the layout as necessary.
For example, if a news application has two fragments in an activity—one to show a list of articles (fragment A) and another to display an article (fragment B)—then fragment A must tell the activity when a list item is selected so that it can tell fragment B to display the article. In this case, the OnArticleSelectedListener
interface is declared inside fragment A:
public static class FragmentA extends ListFragment { ... // Container Activity must implement this interface public interface OnArticleSelectedListener { public void onArticleSelected(Uri articleUri); } ... }
Then the activity that hosts the fragment implements the OnArticleSelectedListener
interface and overridesonArticleSelected()
to notify fragment B of the event from fragment A. To ensure that the host activity implements this interface, fragment A's onAttach()
callback method (which the system calls when adding the fragment to the activity) instantiates an instance of OnArticleSelectedListener
by casting the Activity
that is passed into onAttach()
:
public static class FragmentA extends ListFragment { OnArticleSelectedListener mListener; ... @Override public void onAttach(Activity activity) { super.onAttach(activity); try { mListener = (OnArticleSelectedListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener"); } } ... }
If the activity has not implemented the interface, then the fragment throws a ClassCastException
. On success, the mListener
member holds a reference to activity's implementation of OnArticleSelectedListener
, so that fragment A can share events with the activity by calling methods defined by the OnArticleSelectedListener
interface. For example, if fragment A is an extension of ListFragment
, each time the user clicks a list item, the system calls onListItemClick()
in the fragment, which then calls onArticleSelected()
to share the event with the activity:
public static class FragmentA extends ListFragment {
OnArticleSelectedListener mListener;
...
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
// Append the clicked item's row ID with the content provider Uri
Uri noteUri = ContentUris.withAppendedId
(ArticleColumns.CONTENT_URI, id);
// Send the event and Uri to the host activity
mListener.onArticleSelected(noteUri);
}
...
}
The id
parameter passed to onListItemClick()
is the row ID of the clicked item, which the activity (or other fragment) uses to fetch the article from the application's ContentProvider
.
More information about using a content provider is available in the Content Providers document.
Adding items to the Action Bar
Your fragments can contribute menu items to the activity's Options Menu (and, consequently, the Action Bar) by implementing onCreateOptionsMenu()
. In order for this method to receive calls, however, you must callsetHasOptionsMenu()
during onCreate()
, to indicate that the fragment would like to add items to the Options Menu (otherwise, the fragment will not receive a call to onCreateOptionsMenu()
).
Any items that you then add to the Options Menu from the fragment are appended to the existing menu items. The fragment also receives callbacks to onOptionsItemSelected()
when a menu item is selected.
You can also register a view in your fragment layout to provide a context menu by callingregisterForContextMenu()
. When the user opens the context menu, the fragment receives a call toonCreateContextMenu()
. When the user selects an item, the fragment receives a call toonContextItemSelected()
.
Note: Although your fragment receives an on-item-selected callback for each menu item it adds, the activity is first to receive the respective callback when the user selects a menu item. If the activity's implementation of the on-item-selected callback does not handle the selected item, then the event is passed to the fragment's callback. This is true for the Options Menu and context menus.
For more information about menus, see the Menus and Action Bar developer guides.
Handling the Fragment Lifecycle

Figure 3. The effect of the activity lifecycle on the fragment lifecycle.
Managing the lifecycle of a fragment is a lot like managing the lifecycle of an activity. Like an activity, a fragment can exist in three states:
-
Resumed
- The fragment is visible in the running activity. Paused
- Another activity is in the foreground and has focus, but the activity in which this fragment lives is still visible (the foreground activity is partially transparent or doesn't cover the entire screen). Stopped
- The fragment is not visible. Either the host activity has been stopped or the fragment has been removed from the activity but added to the back stack. A stopped fragment is still alive (all state and member information is retained by the system). However, it is no longer visible to the user and will be killed if the activity is killed.
Also like an activity, you can retain the state of a fragment using a Bundle
, in case the activity's process is killed and you need to restore the fragment state when the activity is recreated. You can save the state during the fragment'sonSaveInstanceState()
callback and restore it during either onCreate()
, onCreateView()
, oronActivityCreated()
. For more information about saving state, see the Activities document.
The most significant difference in lifecycle between an activity and a fragment is how one is stored in its respective back stack. An activity is placed into a back stack of activities that's managed by the system when it's stopped, by default (so that the user can navigate back to it with the Back button, as discussed in Tasks and Back Stack). However, a fragment is placed into a back stack managed by the host activity only when you explicitly request that the instance be saved by calling addToBackStack()
during a transaction that removes the fragment.
Otherwise, managing the fragment lifecycle is very similar to managing the activity lifecycle. So, the same practices for managing the activity lifecycle also apply to fragments. What you also need to understand, though, is how the life of the activity affects the life of the fragment.
Caution: If you need a Context
object within your Fragment
, you can call getActivity()
. However, be careful to call getActivity()
only when the fragment is attached to an activity. When the fragment is not yet attached, or was detached during the end of its lifecycle, getActivity()
will return null.
Coordinating with the activity lifecycle
The lifecycle of the activity in which the fragment lives directly affects the lifecycle of the fragment, such that each lifecycle callback for the activity results in a similar callback for each fragment. For example, when the activity receives onPause()
, each fragment in the activity receives onPause()
.
Fragments have a few extra lifecycle callbacks, however, that handle unique interaction with the activity in order to perform actions such as build and destroy the fragment's UI. These additional callback methods are:
-
Called when the fragment has been associated with the activity (the
Activity
is passed in here). - Called to create the view hierarchy associated with the fragment.
-
Called when the activity's
onCreate()
method has returned. - Called when the view hierarchy associated with the fragment is being removed.
- Called when the fragment is being disassociated from the activity.
onAttach()
onCreateView()
onActivityCreated()
onDestroyView()
onDetach()
The flow of a fragment's lifecycle, as it is affected by its host activity, is illustrated by figure 3. In this figure, you can see how each successive state of the activity determines which callback methods a fragment may receive. For example, when the activity has received its onCreate()
callback, a fragment in the activity receives no more than the onActivityCreated()
callback.
Once the activity reaches the resumed state, you can freely add and remove fragments to the activity. Thus, only while the activity is in the resumed state can the lifecycle of a fragment change independently.
However, when the activity leaves the resumed state, the fragment again is pushed through its lifecycle by the activity.
Example
To bring everything discussed in this document together, here's an example of an activity using two fragments to create a two-pane layout. The activity below includes one fragment to show a list of Shakespeare play titles and another to show a summary of the play when selected from the list. It also demonstrates how to provide different configurations of the fragments, based on the screen configuration.
Note: The complete source code for this activity is available in FragmentLayout.java
.
The main activity applies a layout in the usual way, during onCreate()
:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.fragment_layout); }
The layout applied is fragment_layout.xml
:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment" android:id="@+id/titles" android:layout_weight="1" android:layout_width="0px" android:layout_height="match_parent" /> <FrameLayout android:id="@+id/details" android:layout_weight="1" android:layout_width="0px" android:layout_height="match_parent" android:background="?android:attr/detailsElementBackground" /> </LinearLayout>
Using this layout, the system instantiates the TitlesFragment
(which lists the play titles) as soon as the activity loads the layout, while the FrameLayout
(where the fragment for showing the play summary will go) consumes space on the right side of the screen, but remains empty at first. As you'll see below, it's not until the user selects an item from the list that a fragment is placed into the FrameLayout
.
However, not all screen configurations are wide enough to show both the list of plays and the summary, side by side. So, the layout above is used only for the landscape screen configuration, by saving it at res/layout-land/fragment_layout.xml
.
Thus, when the screen is in portrait orientation, the system applies the following layout, which is saved atres/layout/fragment_layout.xml
:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment" android:id="@+id/titles" android:layout_width="match_parent" android:layout_height="match_parent" /> </FrameLayout>
This layout includes only TitlesFragment
. This means that, when the device is in portrait orientation, only the list of play titles is visible. So, when the user clicks a list item in this configuration, the application will start a new activity to show the summary, instead of loading a second fragment.
Next, you can see how this is accomplished in the fragment classes. First is TitlesFragment
, which shows the list of Shakespeare play titles. This fragment extends ListFragment
and relies on it to handle most of the list view work.
As you inspect this code, notice that there are two possible behaviors when the user clicks a list item: depending on which of the two layouts is active, it can either create and display a new fragment to show the details in the same activity (adding the fragment to the FrameLayout
), or start a new activity (where the fragment can be shown).
public static class TitlesFragment extends ListFragment { boolean mDualPane; int mCurCheckPosition = 0; @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // Populate list with our static array of titles. setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_activated_1, Shakespeare.TITLES)); // Check to see if we have a frame in which to embed the details // fragment directly in the containing UI. View detailsFrame = getActivity().findViewById(R.id.details); mDualPane = detailsFrame != null && detailsFrame.getVisibility() == View.VISIBLE; if (savedInstanceState != null) { // Restore last state for checked position. mCurCheckPosition = savedInstanceState.getInt("curChoice", 0); } if (mDualPane) { // In dual-pane mode, the list view highlights the selected item. getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); // Make sure our UI is in the correct state. showDetails(mCurCheckPosition); } } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt("curChoice", mCurCheckPosition); } @Override public void onListItemClick(ListView l, View v, int position, long id) { showDetails(position); } /** * Helper function to show the details of a selected item, either by * displaying a fragment in-place in the current UI, or starting a * whole new activity in which it is displayed. */ void showDetails(int index) { mCurCheckPosition = index; if (mDualPane) { // We can display everything in-place with fragments, so update // the list to highlight the selected item and show the data. getListView().setItemChecked(index, true); // Check what fragment is currently shown, replace if needed. DetailsFragment details = (DetailsFragment) getFragmentManager().findFragmentById(R.id.details); if (details == null || details.getShownIndex() != index) { // Make new fragment to show this selection. details = DetailsFragment.newInstance(index); // Execute a transaction, replacing any existing fragment // with this one inside the frame. FragmentTransaction ft = getFragmentManager().beginTransaction(); if (index == 0) { ft.replace(R.id.details, details); } else { ft.replace(R.id.a_item, details); } ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); ft.commit(); } } else { // Otherwise we need to launch a new activity to display // the dialog fragment with selected text. Intent intent = new Intent(); intent.setClass(getActivity(), DetailsActivity.class); intent.putExtra("index", index); startActivity(intent); } } }
The second fragment, DetailsFragment
shows the play summary for the item selected from the list fromTitlesFragment
:
public static class DetailsFragment extends Fragment { /** * Create a new instance of DetailsFragment, initialized to * show the text at 'index'. */ public static DetailsFragment newInstance(int index) { DetailsFragment f = new DetailsFragment(); // Supply index input as an argument. Bundle args = new Bundle(); args.putInt("index", index); f.setArguments(args); return f; } public int getShownIndex() { return getArguments().getInt("index", 0); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if (container == null) { // We have different layouts, and in one of them this // fragment's containing frame doesn't exist. The fragment // may still be created from its saved state, but there is // no reason to try to create its view hierarchy because it // won't be displayed. Note this is not needed -- we could // just run the code below, where we would create and return // the view hierarchy; it would just never be used. return null; } ScrollView scroller = new ScrollView(getActivity()); TextView text = new TextView(getActivity()); int padding = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, getActivity().getResources().getDisplayMetrics()); text.setPadding(padding, padding, padding, padding); scroller.addView(text); text.setText(Shakespeare.DIALOGUE[getShownIndex()]); return scroller; } }
Recall from the TitlesFragment
class, that, if the user clicks a list item and the current layout does not include the R.id.details
view (which is where the DetailsFragment
belongs), then the application starts theDetailsActivity
activity to display the content of the item.
Here is the DetailsActivity
, which simply embeds the DetailsFragment
to display the selected play summary when the screen is in portrait orientation:
public static class DetailsActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { // If the screen is now in landscape mode, we can show the // dialog in-line with the list so we don't need this activity. finish(); return; } if (savedInstanceState == null) { // During initial setup, plug in the details fragment. DetailsFragment details = new DetailsFragment(); details.setArguments(getIntent().getExtras()); getFragmentManager().beginTransaction().add(android.R.id.content, details).commit(); } } }
Notice that this activity finishes itself if the configuration is landscape, so that the main activity can take over and display the DetailsFragment
alongside the TitlesFragment
. This can happen if the user begins theDetailsActivity
while in portrait orientation, but then rotates to landscape (which restarts the current activity).
For more samples using fragments (and complete source files for this example), see the API Demos sample app available in ApiDemos (available for download from the Samples SDK component).