fragment-Android 6.0开发者文档
fragment-Android 6.0开发者文档
fragment可以完成activity的一部分行为或UI。你可以在一个activity中添加多个fragment,以建立一个多模块的UI,另外,你可以在不同的activity中重用这些fragment。你可以把fragment理解为activity的模块化的一部分,它有自己的生命周期,接收自己的事件,在activity运行时可以动态添加或删除(有点像“子activity”,你可以在不同activity重用它)。
fragment必须植入到activity中,它的生命周期是被宿主activity的生命周期完全影响的。例如,当activity进入paused状态,fragment也会进入paused状态,当activity被销毁,fragment也会被销毁。然而,当activity在运行时(在resumed状态),你可以单独的操作某个fragment,例如添加或删除它们。当你对某个fragment进行操作时,你可以将这个操作添加到由activity管理的一个回退栈中(这个回退栈的每个节点都是某个fragment动作的记录)。这个回退栈可以让用户在按下back按钮后撤销fragment动作。
当你将fragment添加到activity的布局中时,它就处于activity视图层的一个ViewGroup中,这时fragment可以定义它自己的视图布局。你可以activity的布局文件中添加
本文档描述了怎样将fragment运用到你的应用中,包括当fragment被加入到activity回退栈时怎样维持自己的状态、fragment怎样与activity和此activity的其他fragment共享事件等等。
设计理念
Android在Android 3.0(API 11)加入fragment功能,最初的目标是在大屏幕上实现更灵活的动态UI设计,如平板上。由于平板的屏幕比手机大很多,也就多出了很多能容纳UI组件的空间。fragment将你从管理复杂的视图层级变化中解救出来。通过将activity的布局分割为多个fragment,你可以在运行时修改activity的界面,并且将这些修改保存到activity管理的回退栈中。
例如,应用可以在界面左边使用一个fragment显示文章列表,在右边显示某个文章的详细信息————这两个fragment处于同一个activity中,一边一个,每个fragment都有自己的生命周期回调方法,并且能分别处理它们自己的输入事件。这样的话,用户就不需要在一个activity选择文章,而另一个activity显示文章了,用户可以在同一个activity中选择文章然后阅读它,就像图1中表现的那样。
你应该将fragment设计为一个模块化、可重复利用的activity组件。每个fragment都有自己的布局和生命周期回调,你可以在不同的activity中使用这个fragment,因此你应该将fragment设计为可重用的,另外你应该避免在fragment中直接操作另一个fragment。重用性对于fragment很重要,因为你需要用fragment的组合去适应不同的屏幕大小。当你将你的应用设计为既支持平板又支持手机时,你可以在不同的布局配置中重用这些fragment,从而让用户可以在不同的屏幕大小中获得最优的体验。一个典型例子是:在手机上,有必要将平板上一个activity可以放下的多个fragment分解为多个activity。
在图1中,当应用运行在平板上时,可以在activity A中放入两个fragment,而在手机上,没有足够的空间能放下两个fragment,所以activity A只包含文章列表的fragment,当用户选择某个文章时,启动activity B,其包含另一个显示文章信息的fragment。这样的话,应用就通过重用fragment同时支持了平板和手机。
创建fragment
你可以通过继承Fragment或Fragment的子类来创建一个fragment。Fragment类的代码看起来很像Activity类。它的回调方法跟activity的回调方法很像,如onCreate()、onStart()、onPause()、onStop()。事实上,如果你的应用想要针对fragment做重构,你会发现activity的回调方法可以很简单的移植到各个fragment中。
通常,对于fragment你需要至少实现以下生命周期方法:
onCreate()
当创建fragment时系统会调用此方法。在此方法中,你应该做一些必要的初始化工作。
onCreateView()
当fragment第一次绘制用户界面时系统会调用此方法。如果你的fragment要绘制UI,你必须在这个方法返回一个表示fragment布局的View,当然,如果你的fragment不需要UI,你可以返回null。
onPause()
当用户离开此fragment时系统会调用此方法。在这个方法中,你应该保存当前用户会话的所有数据,因为用户可能不会回到此fragment了。
应用至少需要为每个fragment实现以上三个方法,当然,你也可以实现其他几个方法来处理fragment的其他生命周期。其他方法的信息请看“处理Fragment生命周期”部分。
除了Fragment基础类,你也可以继承其他几个Fragment的子类:
DialogFragment
表示一个浮动的对话框。使用这个类创建对话框的好处是可以将此fragment加入到activity管理的fragment回退栈中,从而使用户在fragment关闭的情况下可以重新返回此fragment。
ListFragment
显示一个item的列表(列表数据由adapter管理,如SimpleCursorAdapter),类似ListActivity。它提供了几个管理列表view的方法,例如onListItemClick()方法,可以处理点击事件。
PreferenceFragment
显示一个Preference对象的列表,类似PreferenceActivity。它在创建设置界面时很有用。
添加用户界面
fragment通常有自己的布局,并作为activity界面的一部分。
要为fragment添加布局,你必须实现onCreateView()方法,当fragment需要绘制布局时系统会调用它。在这个方法中,你必须返回一个表示此fragment布局的View。
注意:如果你的fragment继承了ListFragment,由于ListFragment的默认实现会在onCreateView()方法中返回一个ListView,所以你可以不实现onCreateView()方法。
你可以用XML定义的layout资源填充一个View作为onCreateView()的返回。系统提供LayoutInflater对象帮助你填充这个View。
使用方法如下(下例中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); } }
onCreateView()的container参数是一个ViewGroup,表示此fragment将要插入的属于activity的父布局。savedInstanceState参数是一个Bundle,其中包含fragment之前保存的数据。
inflate()方法需要三个参数:
你想要填充的布局文件的resource ID 你填充的布局将要插入的ViewGroup。这个参数对于系统很重要,系统会根据它确定填充的布局的根视图的参数(此参数由ViewGroup指定) 一个boolean,表示将填充的布局插入到ViewGroup时是否依附于此ViewGroup。在本例中,这个参数为false,因为系统已经将此填充的布局插入到container中。如果设置为true,将会在最后的布局中创建额外的view group。
将fragment添加到activity中
通常情况下,fragment都作为宿主activity的UI的一部分,并存在于activity的视图层级中。向activity布局添加fragment有两种方法:
在activity的布局文件中声明fragment
系统在创建activity布局时,会实例化布局文件中指定的每个fragment,并调用它们的onCreateView()方法。系统会将此方法返回的View插入到
注意:每个fragment都需要指定一个id,当activity重启时,系统会用此id恢复fragment(你也可以用此id对fragment做一些操作,如移除fragment)。为fragment添加id有三种方式:
添加android:id属性 添加android:tag属性 如果上述两个数据都没有指定,系统会使用fragment容器的id
在ViewGroup中添加fragment
你可以在activity运行的任何时候向activity布局添加fragment。你只需要指定fragment将要放置在的ViewGroup即可。
如果要在activity中操作fragment,你需要使用FragmentTransaction的API。你可以用下例中的代码获取FragmentTransaction:
FragmentManager fragmentManager = getFragmentManager() FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
然后你就可以使用add()方法添加fragment了。代码如下:
ExampleFragment fragment = new ExampleFragment(); fragmentTransaction.add(R.id.fragment_container, fragment); fragmentTransaction.commit();
add()方法的第一个参数是fragment将要插入到的ViewGroup,由resource ID指定,第二个参数是将要插入的fragment。
每次你对fragment做了操作,必须调用commit()方法。
添加没有界面的fragment
添加没有界面的fragment
前面的例子说明了怎样添加有界面的fragment,然而,你也可以为activity添加没有界面的fragment,让它在后台做一些操作。
使用add(Fragment,String)方法可以为activity添加没有界面的fragment(这里的参数为string类型的“tag”,而不是视图ID)。使用这个方法添加fragment是不会收到onCreateView()回调的,所以你不需要实现此方法。
不单单没有界面的fragment可以使用string类型的tag指定,有界面的fragment也可以,只是没有界面的fragment只能用string类型的tag指定而已。如果你想要从activity中获取此没有界面的fragment,你需要调用findFragmentByTag()方法。
管理fragment
管理fragment
在activity中调用getFragmentManager()获取FragmentManager,可以管理此activity的fragment。
使用FragmentManager,你可以:
用findFragmentById()或findFragmentByTag()方法获取activity的某个fragment 用popBackStack()方法从回退栈中弹出fragment(模拟用户点击返回键) 用addOnBackStackChangedListener()方法注册一个监听器,以监听回退栈的变化
在前面的部分,我们也提到可以使用FragmentManager开始一个FragmentTransaction,从而进行添加、删除fragment等操作。
更多信息请看FragmentManager类的文档部分。
fragment事务
fragment事务
在activity中使用fragment有一个特性:你可以添加、删除、替换或对fragment进行其他操作,来作为对用户动作的响应。每个你提交给activity的fragment变化称为一个事务(transaction),你可以用FragmentTransaction中的API执行这些事务。你可以将事务添加到activity管理的回退栈中,从而允许用户撤销操作。
你可以用下列代码获取FragmentTransaction:
FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
事务包含了你想要在一次事务中进行的若干操作。你可以用add()、remove()、replace()等方法为指定事务设置操作。然后,你可以用commit()方法将事务提交给activity。
在调用commit()方法之前,你可以调用addToBackStack()方法将事务加入到fragment事务的回退栈中。这个回退栈由activity管理,可以实现用户点击返回键后回到上一个fragment状态的功能。
下例中,描述了怎样替换fragment,并且将状态保存到回退栈中:
// 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();
在这个例子中,newFragment替换了原来的fragment,并将替换操作保存在回退栈中,当用户点击返回键时,此次替换将会被撤销,之前的fragment会重新显示。
如果你在一次事务中进行了多次操作,然后调用addToBackStack(),那么用户点击返回键后所有的操作都会被撤销。
操作在FragmentTransaction中的顺序不重要,但是注意:
最后调用commit() 如果你在同一个容器中添加了多个fragment,那么这些fragment在视图层级的顺序将取决于你添加的顺序
如果你在事务中移除了某个fragment,但是没有调用addToBackStack(),那么当此次事务被提交后,此fragment会被销毁,用户将不能返回到这个fragment。然而,如果你调用了addToBackStack(),那么此fragment会进入stopped状态,当用户返回时它会重新进入resumed状态。
注意:你可以在commit前调用setTransaction()方法为事务添加过渡动画。
调用commit()方法后事务不会立刻被执行,而是提交到activity的UI线程执行队列中,由线程空闲时执行。你可以在UI现场中调用executePendingTransaction()方法来立刻执行commit()方法提交的事务。通常你不需要这样做,除非在其他线程有工作依赖于此事务。
注意:你只能在用户离开activity前使用commit()提交事务,否则会抛出异常。这是为了防止在activity恢复后丢失提交的状态。如果你可以接受提交失败,那么可以调用commitAllowingStateLoss()方法。
与activity通信
与activity通信
虽然fragment的实现不依赖于某个activity,而且可以被用于多个activity中,但是fragment实例仍然跟它的宿主activity紧密的联系在一起。
fragment可以使用getActivity()方法访问宿主activity,从而可以很方便的执行一些任务,如在activity布局中寻找某个view:
View listView = getActivity().findViewById(R.id.list);
同样的,宿主activity可以调用FragmentManager的findFragmentById()或findFragmentByTag()方法获得Fragment实例:
ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);
在activity注册事件回调
在activity注册事件回调
在某些情况下,你可能需要fragment分享事件给activity。一个好的做法是:fragment定义一个回调接口,然后宿主activity实现它。当activity收到此回调时,它就可以将信息分享给其他fragment了。
例如,如果你的activity有两个fragment,一个显示文章列表(fragment A),另一个显示文章信息(fragment B)。那么fragment A必须通知activity某篇文章被选中了,这样activity才能通知fragment B显示此文章。在下面的例子中,fragment A声明了一个OnArticleSelectedListener接口:
public static class FragmentA extends ListFragment { ... // Container Activity must implement this interface public interface OnArticleSelectedListener { public void onArticleSelected(Uri articleUri); } ... }
然后activity实现OnArticleSelectedListener接口,并override其onArticleSelected方法,在此方法中activity将fragment A的信息通知给fragment B。为了确保宿主activity实现了此接口,fragment A可以在onAttach()方法中尝试实例化activity的OnArticleSelectedListener:
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"); } } ... }
如果activity没有实现此接口,那么fragment A会抛出ClassCastException。如果activity实现了此接口,那么fragment A就可以通过调用OnArticleSelectedListener的onArticleSelected方法向activity分享事件了。本例中,fragment A继承了ListFragment,每当用户点击了某个item,那么系统会通过onListItemClick()通知fragment A,然后fragment A调用onArticleSelected方法分享事件给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); } ... }
为action bar添加item
为action bar添加item
你的fragment可以通过实现onCreateOptionsMenu()方法为activity的菜单(options menu)添加选项。为了让此方法被调用,你必须在onCreate()方法中调用setHasOptionsMenu(),来表明你的fragment会向菜单添加选项(否则你的fragment的onCreateOptionsMenu()方法不会被调用)。
你通过fragment添加的选择会被加入到已经存在的菜单中。当它添加的选择被点击时,fragment会通过onOptionsItemSelected()方法获取回调。
你也可以通过调用registerForContextMenu()方法将fragment布局中的view添加到系统菜单(context menu)中。当用户打开系统菜单时,fragment会在onCreateContextMenu()方法获取回调。当用户选择了某个选项时,fragment可以通过onContextItemSelected()方法获得回调。
注意:当用户点击菜单时,虽然你的fragment可以获取相关回调,但是activity会更早的获取回调。只有activity的回调没有处理此事件,你的fragment才会被通知
处理fragment生命周期
处理fragment生命周期
管理fragment的生命周期跟管理activity的生命周期类似。fragment也存在三个状态:
resumed。表示此fragment在当前activity是可见的 paused。表示另一个activity在前台且拥有焦点,而fragment所在的activity仍然可见(前台activity部分透明或没有占满整个屏幕) stopped。表示此fragment不可见。可能是宿主activity被停止或者fragment被移除出activity并加入到回退栈中。处于stopped状态的fragment仍然存活,它的状态和信息仍然被系统保存着。然而此fragment已经对用户不可见,而且当activity被kill的时候它也会被kill
类似于activity,你可以用bundle保存fragment状态,用于activity进程被kill后重新创建时恢复fragment状态。你可以在fragment的onSaveInstanceState()方法保存状态,并在onCreate()方法、onCreateView()方法、onActivityCreated()方法恢复。
activity与fragment生命周期的不同主要体现在回退栈上。默认情况下,当activity被stopped的时候,会被压入系统管理的activity回退栈中。而fragment只有在移除fragment的事务中,主动要求加入回退栈(调用addToBackStack()方法),才会被压入宿主activity管理的回退栈中。
此外,管理fragment生命周期很像管理activity生命周期。你可以参考activity的生命周期管理文档。你真正需要在这个文档了解的,是activity的生命周期怎样影响fragment的生命周期。
注意:如果你的fragment需要Context对象,可以调用getActivity()方法。然而,只有当fragment已经attach了activity才能调用此方法。如果fragment没有attach了activity,或者已经detached,那么getActivity()会返回null
fragment与activity的生命周期关系
fragment与activity的生命周期关系
activity的生命周期会影响fragment的生命周期。例如,当activity调用onPause()时,每个fragment都会调用onPause()。
fragment有一些特有的生命周期回调方法,以处理与activity的独特的交互,比如创建或销毁fragment的UI。这些特有的回调方法包括:
onAttach()。当fragment与activity绑定的时候会调用 onCreateView()。创建fragment的界面时调用 onActivityCreated()。当activity的onCreate()方法返回后会调用 onDestroyView()。当fragment的界面被移除时调用 onDetach()。当fragment与activity解绑的时候调用
activity的生命周期与fragment的生命周期的关系,已经在图3中说明了。
activity进入resumed状态后,你可以*的向此activity添加或移除fragment。因此,只有当activity进入resumed状态,fragment的生命周期变化才是独立的。
当activity退出resumed状态,fragment的生命周期就再次跟activity结合在一起。
上一篇: maya怎么使用模型复制模式? maya复制模式的使用方法
下一篇: 爆逗,很是佩服这些二货
推荐阅读
-
Services-Android 6.0开发者文档
-
fragment-Android 6.0开发者文档
-
注册开发者数量超400万!华为HMS Core 6.0全球上线
-
七牛开发者文档关于上传凭证,url安全base64得出的数据不同
-
Oracle 10.2.0.1 For CentOS 6.0 安装文档
-
Oracle 10.2.0.1 For CentOS 6.0 安装文档
-
微信支付开发7 收货地址共享接口V2 微信支付接口开发文档 微信支付 开发文档 微信开发者平
-
WinForm框架开发教程 - 多文档界面中的子窗口弹出、拖拽处理 WinFormdevexpressc#.net 6.0
-
fragment-Android 6.0开发者文档
-
微信支付开发7 收货地址共享接口V2 微信支付接口开发文档 微信支付 开发文档 微信开发者平