A Fragment
represents a behavior or a portion of user interface in an Activity
.html
在一个Activity
活动中,一个Fragment
表明一个行为或者用户界面的一部分java
You can combine multiple fragments in a single activity to build a multi-pane UI and reuse a fragment in multiple activities.android
你能够将多个碎片组合到一个活动中,来构成多面UI并能够在多个活动中重复使用一个碎片编程
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).api
你能够将一个碎片当成一个活动的模块化的部分,它有本身生命周期,接收它本身捅有的输入事件,而且当活动正在运行时,你能够增长和移除它(稍稍有点像是,能够在不一样的活动中重复使用的子活动)。sass
A fragment must always be embedded in an activity and the fragment's lifecycle is directly affected by the host activity's lifecycle.session
一个碎片老是嵌入到一个活动中的,而且碎片的生命周期直接由捅有它的主活动的生命周期所影响app
For example, when the activity is paused, so are all fragments in it, and when the activity is destroyed, so are all fragments.less
好比,当活动被暂停了,那么全部其中的片段也会暂停,而且当活动被中止了,因此全部的碎片也被中止了ide
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.
当你运行这样一个碎片事务时,你也能够把它加入到由activity管理的返回堆中,在活动中每一个返回堆的入点是每一个碎片事务发生的一个记录.
The back stack allows the user to reverse a fragment transaction (navigate backwards), by pressing the BACK button.
在按返回键时,返回堆容许用反转碎片事务(导航返回)
When you add a fragment as a part of your activity layout, it lives in a ViewGroup
inside the activity's view hierarchy and the fragment defines its own view layout.
当你把一个碎片,加入到你的活动布局中的一部分时,它存在于一个嵌入了活动的视图层级的ViewGroup中
.而且碎片定义它本身的视图布局
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
.
你能够用<fragment>
元素,在活动的布局文件中声明一个碎片,插入到你的活动的布局中,或者在应用代码中,把它加入到一个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.
然而,一个碎片不是活动布局必需要求的一部分,你也能够用一个没有它本身的UI的碎片,把它当成活动的一个不可见的工做者.
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.
这个文档描述了,如何构建一个应用来使用碎片,包括把碎片加入到活动的返回堆时,怎样维持它们的状态.与活动和该活动的其余碎片共享事件,构成(促成)活动的动做条等.
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.
Android在3.0中包含了碎片,主要是为在大屏幕布中支持更加动态和灵活的UI,好比平板电脑
Because a tablet's screen is much larger than that of a handset, there's more room to combine and interchange UI components.
由于平板电脑的屏幕布比手持设备大不少,它有更多的空间来组合和交换UI组件
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.
碎片的设计,能使你不须要管理复杂的视图层的的改变.经过把你的视图布局分红碎片,你就能在运行时修改活动的显示,而且把这些改变保存在由活动管理的一个返回堆中.
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.
所以,用户就能在同一个活动中选择文章并阅它,而不须要用一个活动选一篇文章,另外一个活动去读取文章.就像图1中平板电脑布局中显示的同样.
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.
好比,在一个手持设备中,可能必要把一个碎片从单个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,说明了,两个碎片UI模块在平板电脑中,怎样结合到一个活动中,但在手持设备中是怎样分开的.
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.
好比----继续使用新闻应用的例子,当在平板电脑中运行时,这个应用能够嵌入两个碎片到活动A中,
However, on a handset-sized screen, there's not be 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.
因此活动A,只包括显示文章列表的碎片,并当用户选择了一篇文章时,它启动活动B,而活动B包括了读取文章的第二个碎片. Thus, the application supports both tablets and handsets by reusing fragments in different combinations, as illustrated in figure 1.所以,就像图1同样,应用经过重用碎片的不一样组合,来同时支持平板电脑和手持设备.For more information about designing your application with different fragment combinations for different screen configurations, see the guide to Supporting Tablets and Handsets.更多关于使用不一样碎片组合,来设计你的应用支持不一样屏幕配置的信息,请看Supporting Tablets and Handsets.
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
. 要建立碎片,你必须建立一个Fragment
子类(或者它存在的子类),Fragment
类的代码看起来像是一个Activity
类.It contains callback methods similar to an activity, such as onCreate()
, onStart()
, onPause()
, and onStop()
. 它包含相似于活动的回调方法,好比 onCreate()
, onStart()
, onPause()
,和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.事实上,若是你打算把一个已存在的Android应用,转换成用碎片来实现,你可能只须简单的把你的活动的回调方法中的代码移动到你的碎片的相应的回调方法中.(便可)
Usually, you should implement at least the following lifecycle methods:一般,你应致少实现下面的生命周期方法
onCreate()
onCreateView()
View
from this method that is the root of your fragment's layout. 为了让你的碎片画UI,你必须从这个方法中,返回你的碎片布局的根视图(
View
),You can return null if the fragment does not provide a UI.若是碎片不提供UI,你能够返回空(null)
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 more later, in the section about Handling the Fragment Lifecycle.全部处理生命周期的回调方法,将在Handling the Fragment Lifecycle部分有更多详细的讨论.
There are also a few subclasses that you might want to extend, instead of the base Fragment
class:你还可能想要扩展,除了Fragment
类以外的,其余几个子类,.
DialogFragment
Activity
class,使用这个类建立对话框是,使用
Activity
类中的对话框的可选的好方法. 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.由于你能够把这个碎片对话框合并到由活动管理的碎片返回堆中,这样能容许用户返回到消失的碎片上.
ListFragment
SimpleCursorAdapter
), similar to
ListActivity
. 显示由适配器管理的项目列表(像一个
SimpleCursorAdapter
),相似于
ListActivity
类.It provides several methods for managing a list view, such as the
onListItemClick()
callback to handle click events.它提供了几个管理列表视图的方法,好比处理点击事件的
onListItemClick()
回调方法
PreferenceFragment
Preference
objects as a list, similar to
PreferenceActivity
. This is useful when creating a "settings" activity for your application.把一个
Preference
对象的层次显示成一个列表,相似于
PreferenceActivity
类,当为你的应用建立"setting设置"活动时,这是很是有用的.
A fragment is usually used as part of an activity's user interface and contributes its own layout to the activity.一个碎片经常使用来当成一个活动的用户界面的一部分,并把它本身的布局贡献给活动.
To provide a layout for a fragment, you must implement the onCreateView()
callback method, 为了给一个碎片提供一个布局,你必须实现onCreateView()
回调方法,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.你的这个方法的实现,必须返回你的碎片布局的,根视图(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.注意:若是你的碎片是一个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.为了返回一个布局,你能够展开定义在XML文件中的布局资源(layout resource).为了帮助你这么作(实现他),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);
}
}
In the sample above, 在上面的例子中R.layout.example_fragment
is a reference to a layout resource named example_fragment.xml
saved in the application resources.R.layout.example_fragment
是一个叫example_fragment.xml
布局资源的引用,保存在应用资源中 For information about how to create a layout in XML, see the User Interface documentation.关于如何在XML文件中建立一个布避,看User Interface用户界面文档
The container
parameter passed to onCreateView()
is the parent ViewGroup
(from the activity's layout) 传递给onCreateView()
方法的container
容器参数是父类ViewGroup
(来自活动的布局),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 若是碎片即将被恢复,这个savedInstanceState
参数是一个类,它提供关于前一个碎片实例的数据(restoring state is discussed more in the section about Handling the Fragment Lifecycle).(在Handling the Fragment Lifecycle部分将更详细的讨论重关于新存储状态)
The inflate()
method takes three arguments:inflate()
展开方法包括三个参数
ViewGroup
to be the parent of the inflated layout. ViewGroup
是展开布局的父类 Passing the container
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.为了让系统将布局参数应用到展开的布局的根视图上,传递container
是很是重要,它是由父视图指定(这句很差理解)ViewGroup
(the second parameter) during inflation. 一个布尔值,指示是否展开的布局应该附属到ViewGroup
上(In this case, this is false because the system is already inserting the inflated layout into the container
—passing true would create a redundant view group in the final layout.)在这个例子中,这个值是false ,由于系统已经插入一个展开的视图到容器中---传递真值,将致使在最终的视图上建立一个冗余的视图组.Now you've seen how to create a fragment that provides a layout. Next, you need to add the fragment to your 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. 一般,一个碎片致力于成为宿主活动UI的一部分,There are two ways you can add a fragment to the activity layout:你能够有两个方法来加入一个碎片到活动布局中
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:好比这是一个含有两个碎片的,活动的布局文件的例子
<?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 the Fragment
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 the View
returned by the fragment directly in place of the <fragment>
element.系统将插入<fragment>
元素那儿,由碎片直接返回的视图(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:有三个方法来给碎片提供一个ID:
android:id
attribute with a unique ID.给android:id
属性提供一个惟一的DIandroid:tag
attribute with a unique string.给嘱性提供一个惟一的字串ViewGroup
.或者,可编程的加入一个碎片到一个存在的ViewGroup
At 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运行的任意时刻,你能够添加碎片到你的布局中,你只要简单的为你的碎片指定一个ViewGroup
,在其中放入你的碎片To make fragment transactions in your activity (such as add, remove, or replace a fragment), you must use APIs from FragmentTransaction
.为了处理碎片事务(好比添加,移除,或者替换碎片),你必要使用FragmentTransaction
的APIs .You can get an instance of FragmentTransaction
from your Activity
like this:你能够从你的Activity
活动中获得一个FragmentTransaction
实例.
FragmentManager fragmentManager =
FragmentTransaction fragmentTransaction = fragmentManager.;getFragmentManager()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:你能够用方法加入一个碎片,并指定要加入的碎片和插入到那里.
ExampleFragment fragment = new ExampleFragment();//新建一个碎片
fragmentTransaction.add(R.id.fragment_container, fragment);//第一个是容器,第二个参数是碎片
fragmentTransaction.commit();//提交
The first argument passed to add()
is the ViewGroup
in which the fragment should be placed, specified by resource ID, and the second parameter is the fragment to add.传给add()
方法的,第一个参数是ViewGroup
视图组类,碎片将放在这里,它由资源ID指定,而且第二个参数是要加入的碎片
Once you've made your changes with FragmentTransaction
, you must call commit()
for the changes to take effect.一旦你用FragmentTransaction
改变了你的碎片的事务,你必须调用commit()
方法,使得改变生效.
The examples above show how to add a fragment to your activity in order to provide a UI. 上面的这个例子展现了为了提供一个UI,怎样把一个碎片加入到你的活动中.However, you can also use a fragment to provide a background behavior for the activity without presenting additional UI.然而,你也可使用一个没有显示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).要加入一个没有UI的碎片,从activity中使用方法加入碎片(为碎片,提供一个惟一的字串"tag",而不是视图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.但时,这样增长的碎片,没有关联到活动的布局,它不会从方onCreateView()
法接收一个调用,因此你不须要实现onCreateView()
方法.
Supplying a string tag for the fragment isn't strictly for non-UI fragments为碎片提供字串tag不只仅限于没有UI的碎片—you can also supply string tags to fragments that do have a UI你也能够为有UI的碎片提供字串—but if the fragment does not have a UI, then the string tag is the only way to identify it可是若是碎片没有UI,那么字串tag是惟一能标识它的方法. If you want to get the fragment from the activity later, you need to use findFragmentByTag()
.后续,若是你想要从activity中得到这个碎片,那么你得用这个findFragmentByTag()
方法.
For an example activity that uses a fragment as a background worker, without a UI, see the FragmentRetainInstance.java
sample.想要看一个活动把碎片当成后台工做者的方法,请看 FragmentRetainInstance.java
例子.
To manage the fragments in your activity, you need to use FragmentManager
. To get it, call getFragmentManager()
from your activity.要在你的活动中管理碎片,你须要用FragmentManager
.要获得它,你得用getFragmentManager()
方法.
Some things that you can do with FragmentManager
include:你能够用FragmentManager
类作的事情包括:
findFragmentById()
(for fragments that provide a UI in the activity layout) or findFragmentByTag()
(for fragments that do or don't provide a UI)获取在活动中存大的碎片,用方法(用于在UI布局中提供UI的碎片),或者用findFragmentByTag()
方法(用于提供了或没有提供UI的碎片).popBackStack()
(simulating a BACK command by the user).从返回堆中弹出碎片,用方法(相似于用户用BACK命令)addOnBackStackChangedListener()
.为改变返回堆注册一个监听器,用addOnBackStackChangedListener()
方法.For more information about these methods and others, refer to the FragmentManager
class documentation.关于这些和其余方法的更多信息,参考FragmentManager
类文档
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.就像上面部分所讲的,你能够用FragmentManager
类,来打开一个FragmentTransaction
事务,它能让你执行事务,好比移除碎片
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
. 每一个你提交到活动的一套改变,叫作事务,而且你能在FragmentTransaction
中使用APIs执行一个.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
碎片管理器那里获得一个FragmentTransaction
的实例:
FragmentManager fragmentManager = ;
FragmentTransaction fragmentTransaction = fragmentManager.;getFragmentManager()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()
.而后,应用这些改变到你的活动,你必须用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. 然而,在你调用commit()
方法前,为了加入事务到碎片事务返回堆,你可能想要调用addToBackStack()
方法,This back stack is managed by the activity and allows the user to return to the previous fragment state, by pressing the BACK key.这个返回堆由活动管理,它能容许用户按BACK键返回到前一个碎片状态.
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. 在这个例子中,新的碎片替换了(R.id.fragment_container
)布局容器中的任意碎片.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 BACK key.经过调用方法,替换事务被保存在返回堆中,因此用户按下BACK键,能够反转这个事务到前一个碎片.
If you add multiple changes to the transaction (such as another add()
or remove()
) and call addToBackStack()
, then all changes applied before you call commit()
are added to the back stack as a single transaction and the BACK key will reverse them all together.若是你加入多个改变到事务(好比其余add()
或者remove()
)关且调用addToBackStack()
.在你提交全部改变前,它们被当成一个事务加入到返回堆,而且按BACK键,将把它们一块儿反转.
The order in which you add changes to a FragmentTransaction
doesn't matter, except:你加入到事务的全部改变的先后顺序,可有可无,除了:
commit()
last你必须最后调用方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. 当你执行一个移除碎片的事务时,若是你没有调用addToBackStack()
方法,那么当事务被提交时,那个碎片被销毁了.而且用户不能导航返回到那个碎片.Whereas, if you do call addToBackStack()
when removing a fragment, then the fragment is stopped and will be resumed if the user navigates back.当要移除一个碎片时,若是你调用了addToBackStack()
方法,那么该碎片被中止了,而且若是用户导航返回,它将被恢复.
Tip: For each fragment transaction, you can apply a transition animation, by calling setTransition()
before you commit.在你提交前,经过调用setTransition()
方法.能够对每一个碎片的转换,应用转换动画,
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.调用方法并非当即执行转换,而是一旦主线程可以运行它时,就把它加入活动UI线程(主线程)的运行表里(schedules), If necessary, however, you may call executePendingTransactions()
from your UI thread to immediately execute transactions submitted by commit()
.但如果必须的话,你能够从你的活动UI线程中,调用executePendingTransactions()
方法当即执行由commit()
提交的转换(transactions) 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).注意,你只能在活动保存它的状态以前(当用户),用commit()
方法提交事务. 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()
.对于你的提交能够被丢掉的状况,那么你就用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.虽然Fragment
是看成一个独立于Activity
的对象实现的,而且能够插入到多个活动,但一个给定的对象,是直接捆邦包含它的活动上的。
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
from FragmentManager
, using findFragmentById()
or findFragmentByTag()
. For example:一样,你的活动可通findFragmentById()
或者findFragmentByTag()
方法从FragmentManager
中查询的Fragment
引用,调用碎片里的方法,好比:
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. 好比说,若是一个应用在一个活动中有两个碎片,一个用于显示文章列表(碎片A),而且另外一个用于显示文章内容(碎片B)---然而,碎片A必须告诉碎片B,列表中的那一项被选中了,好让碎片B能显示选中项所对应的文章,In this case, the OnArticleSelectedListener
interface is declared inside fragment A:在这种状况下,碎片A中声明了OnArticleSelectedListener
监听接口:
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 overrides onArticleSelected()
to notify fragment B of the event from fragment A. 该碎片的宿主活动,实现OnArticleSelectedListener
接口并复写onArticleSelected()
方法,告诉碎片B一个来自碎片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()
:为了保证宿主活动实现这个实例,碎片AonAttach()
回调方法(当把该碎片加入到该活动时系统会调用该方法),通传给onAttach()
方法该Activity
,并把它抛出。
public static class FragmentA extends ListFragment { OnArticleSelectedListener mListener; ... @Override public void onAttach(Activity activity) { super.onAttach(activity); try { mListener = (OnArticleSelectedListener) activity;//活动必须实现OnArticleSelectedListener接口,不然转换异常 } 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
. 若是该活动没有实现该接口,那么碎片会抛出一个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.在成功的状况下,mListener
的成员持有活动的OnArticleSelectedListener
实现的引用 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:好比,若是一个碎片A继承了ListFragment
类,每次用户点击一个列表项,系统调用碎片中的onListItemClick()
方法,并在该方法中调用onArticleSelected()
方法,来与活动共享事件
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);//把选定的列表项ID,包裹成Uri // Send the event and Uri to the host activity mListener.onArticleSelected(noteUri);//经过该方法发送到活动,活动实现了这个方法,而后解释该Uri,再传给该活动的其余碎片 } ... }
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
.传给onListItemClick()
)方法的id参数是点击项的行ID.活动将用该ID,从应用的内容提供者ContentProvider
获取文章.
More information about using a content provider is available in the Content Providers document.关于怎样使用内容提供者请看Content Providers 文档
Your fragments can contribute menu items to the activity's Options Menu (and, consequently, the Action Bar) by implementing onCreateOptionsMenu()
.你的碎片能够经过实现onCreateOptionsMenu()
方法把菜单项贡献给活动Options Menu可选菜单(而且,一样,可贡献给Action Bar) In order for this method to receive calls, however, you must call setHasOptionsMenu()
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()
).然而,为了让这个方法收到调用,你必须在onCreate()
里调用setHasOptionsMenu()
方法,来表示碎片想加入items项到可选菜单中(不然,碎片将不能收到来自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.当菜单项被选中时,碎片也会收到onOptionsItemSelected()
的回调.
You can also register a view in your fragment layout to provide a context menu by calling registerForContextMenu()
. 你也能够调用registerForContextMenu()
方法,将你碎片布局中的视图注册到上下文菜单,When the user opens the context menu, the fragment receives a call to onCreateContextMenu()
. 当用户打开上下文菜单,碎片将收到来自onCreateContextMenu()
方法的调用When the user selects an item, the fragment receives a call to onContextItemSelected()
.当用户选择一个项时,碎片将收到onContextItemSelected()
调用.
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. 当用户选中一个菜单项时,虽然你的碎片收到它加入的到菜单的每个项的响应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. 若是活动的响应项选择(on-item-selected)的实现没有处理选择的项,那么事件将被传到碎片的回调.This is true for the Options Menu and context menus.对于选择菜单和上下文菜单这是真的
For more information about menus, see the Menus and Action Bar developer guides.关于菜单的详细状况,请看Menus和Action Bar(动做条)开发指南
Figure 3. The activity lifecycle's affect on the fragment lifecycle.图3是活动的生命周期对关于碎片的影响
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:管理碎片的生命周期,很像管理活动的生命周期,就像活动同样,一个碎片能够存在下面三种状态
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. 像活动同样,你也能够用来Bundle
记住碎片的状态,在活动的进程被杀掉后,当再次从新建立活动时,你须要恢复碎片的状态。You can save the state during the fragment's onSaveInstanceState()
callback and restore it during either onCreate()
, onCreateView()
, or onActivityCreated()
.你能够在碎片的onSaveInstanceState()
回调方法中保存状态,并可在这onCreate()
, onCreateView()
, 或onActivityCreated
几个方法中恢复它 For more information about saving state, see the Activities document.更多关于保存状态的信息,请看Activities文档
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 key, as discussed in Tasks and Back Stack)默认状况下,当活动中止时,它被存放在由系统管理的活动返回堆中(因此用户能够用BACK键导航返回它,就像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然而,一个碎片保存在该碎片的宿主活动所管理的返回堆中,仅当在转换中移除一个碎片时,你显式的调用了addToBackStack()
保存一个实例的请求的状况下才发生,.
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.虽然如此,但你也须要知道,活动的生命周期是如何影响碎片的生命周期的.
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()
.好比,当一个活动收到一个onPause()
方法调用,该活动中的每一个碎片将收到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:碎片还有其余的生命周期回调。那是为了执行像构建和销毁碎片的UI动做,所须要与活动之间处理的比较特别的交互.这些另外回调方法是
onAttach()
Activity
is passed in here). 当碎片已经关联到活动时,补调用(
Activity
活动被传到这个方法)
onCreateView()
onActivityCreated()
onCreate()
method has returned. 当活动
onCreate()
方法已经返回时,调用.
onDestroyView()
onDetach()
The flow of a fragment's lifecycle, as it is affected by its host activity, is illustrated by figure 3.图3说明了碎片的生命周期,就像它的宿主活动所影响的同样。 In this figure, you can see how each successive state of the activity determines which callback methods a fragment may receive. 在这个图中,你能够看到活动的每一个正常的(succesive)状态,怎么决定碎片可能收到的回调方法的。For example, when the activity has received its onCreate()
callback, a fragment in the activity receives no more than the onActivityCreated()
callback.好比,当该活动已收到它的onCreate()
方法,该活动中的一个碎片将不仅收到onActivityCreated()
回调方法.(意思是,它还会收到其余方法)
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
.注意,这个例子的完整的代码在FragmentLayout.java
这里.
The main activity applies a layout in the usual way, during onCreate()
:像平时同样,主活动在onCreate()
中应用一个布局:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_layout);
}
The layout applied is fragment_layout.xml
://该布局是一个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. 使用这个布局,当活动装载布局时,系统将尽快实例化标题碎片(TitlesFragment
),(它用于列出标题),同时帧布局FrameLayout
(碎片将在这块空间显示摘要)将占用屏幕右边的空间,但开始这里还是空的.。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
.你像你下面所看到的,直到用户从列表中选中一个时,碎片将被放到帧布局中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
.因此,上面的布局只适用于横向配置的屏幕,经过保存到res/layout-land/fragment_layout.xml中.
Thus, when the screen is in portrait orientation, the system applies the following layout, which is saved at res/layout/fragment_layout.xml
:所以,当屏幕是竖向时,系统应用下面这个布局,该布局保存在res/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
. 这个布局只包括标题碎片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. 首先是标题列表碎片TitlesFragment
,它显示莎士比亚的话剧标题列表.This fragment extends ListFragment
and relies on it to handle most of the list view work.这个碎片继承ListFragment
类,而且依赖该类处理大多数列表视图工做。
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();
ft.replace(R.id.details, 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 from TitlesFragment
:第二个碎片,显示从标题列表中选中的项的摘要:
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 the DetailsActivity
activity to display the content of the item.若是用户点一个列表项,而且当前布局没有包括R.id.details
视图,TitlesFragment
类将再次调用,而后应用将开启一个新的DetailsActivity
活动来显示该项的详细内容
Here is the DetailsActivity
, which simply embeds the DetailsFragment
to display the selected play summary when the screen is in portrait orientation:当屏幕是竖向时,这个DetailsActivity
活动,简单的嵌入了一个DetailsFragment
,来显示选中的话剧摘要:
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
.注意,若是配置是横向的这个活动结束它本身,因此主活动能接管而且显示DetailsFragment
详细碎片在TitlesFragment
标题碎片旁边。 This can happen if the user begins the DetailsActivity
while in portrait orientation, but then rotates to landscape (which restarts the current activity).这种状况发生在,当是竖向时,用户开始DetailsActivity
详细碎片,而后,又转向到了横向(这将会重启当前活动)
For more samples using fragments (and complete source files for this example), see the sample code available in ApiDemos (available for download from the Samples SDK component).使用碎片的更多例子(及这个例子的完整的代码),看例子代码在ApiDemos中(从下载的Samples SDK component可用.)