1617Android开发技术讲义 之分段FragmentWord文档下载推荐.docx
《1617Android开发技术讲义 之分段FragmentWord文档下载推荐.docx》由会员分享,可在线阅读,更多相关《1617Android开发技术讲义 之分段FragmentWord文档下载推荐.docx(12页珍藏版)》请在冰豆网上搜索。
因此,取代掉一个activity选择文章,而另一个activity来显示文章,用户可以选择一遍文章,并在同一个activity中阅读。
如下图
你应该把每个Fragment设计成一个模块,并且是可服用的activity组件。
也就是,因为每个Fragment定义了它自己的布局和它自己的行为(通过它自己的生命周期方法),你可以把一个Fragment包含在多个activity中,因此,你应该设计成可复用的,并且避免从一个Fragment中直接操作另一个Fragment。
这尤其重要,因为模块化的Fragment允许你针对不同的屏幕大小来改变你的Fragment的组合方式。
当你的app既支持平板又支持手持式设备的时候,你可以在不同的布局配置中复用你的Fragment,从而优化用户基于可用屏幕空间的体验。
还接着以新闻app为例,当app运行在平板的时候,app的activityA中可以包含两个Fragment,然而,在手持式设备中,没有足够的空间放下两个Fragment,因此,activityA只包含用于显示文章列表的Fragment,当用户选择了一篇文章,它启动了activityB,该activity中包含第二个Fragment用来阅读文章。
因此,app通过复用Fragmen,采用不同组合,从而支持了平板和手持式设备。
如上图。
创建一个Fragment
为了创建一个Fragment,你必须创建一个Fragment的一个子类(或者是子类的子类)。
Fragment类和Activity类很像。
它包含的回调方法同activity相似,比如:
onCreate(),onStart(),onPause(),及onStop()。
如果你把某个以前的android应用转换成使用Fragment的app,你可以只是简单的把原来activity的回调方法中的代码复制到对应的Fragment的回调方法中去就可以了。
通常,你应该实现至少下面几个生命周期方法:
onCreate()
当系统创建Fragment的时候调用。
在你的实现中,你应该初始化Fragment暂停、停止及运行时需要保持的基本的Fragment组件。
nCreateView()
当Fragment第一次绘制它的UI的时候调用该方法。
为了绘制你的Fragment的UI,你必须返回从这个方法中返回一个View,该view是你的Fragment布局的根。
如果你的Fragment不提供UI,你可以返回null。
onPause()
作为第一个用户离开Fragment的指示(尽管不总是意味着Fragment被销毁),系统调用该方法。
在这个方法中你应该提交任何需要保持的变化(因为用户可能不再回来)
大部分的app应该为Fragment实现至少这三个方法。
还有一些其他的回调方法处理Fragment生命周期的不同阶段。
有一些你可能会经常继承的子类:
DialogFragment
显示一个浮动的对话框。
使用本类来创建对话框比使用Activity类中的对话框帮助方法要好。
以为你可以把对话框Fragment放入back栈,从而用户可以回撤到消失的Fragment。
ListFragment
显示通过一个适配器(比如SimpleCursorAdaptor)所管理的列表,类似于ListActivity。
它提供了一些方法来管理list视图,比如onListItemClick()来处理单击事件。
PreferenceFragment
把Preference对象的层次作为一个列表显示出来,类似于PreferenceActivity。
当你需要为你的app创建一个“设置”activity的时候,这比较有用。
添加UI
一个Fragment通常作为activity的UI的一部分。
通过实现onCreateView()这个回调方法,在该方法中应用Fragment的布局。
当系统绘制Fragment的布局的时候,android系统会调用该回调方法。
你对该方法的实现中必须返回你的Fragment布局中的根View。
注意:
如果你的Fragment是ListFragment的子类,在onCreateView()中默认返回一个ListView,所以你不需要实现该回调方法。
为了从onCreateView()中返回布局,你需要把这个布局从布局资源XML文件中应用,为了这些做,onCreateView()方法中传入了一个LayoutInflater对象。
下例从example_fragment.xml文件中调入一个布局:
publicstaticclassExampleFragmentextendsFragment{
@Override
publicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,
BundlesavedInstanceState){
//Inflatethelayoutforthisfragment
returninflater.inflate(R.layout.example_fragment,container,false);
}
}
传递给onCreateView()的container参数为Fragment布局将要插入的ViewGroup。
SavedInstanceState参数为Bundle,该参数为该Fragment的前一个实例的数据,如果这个Fragment被回复的时候,它的状态也会被恢复。
inflate()方法有三个参数:
●你要去应用的布局ID
●被应用布局所在的ViewGroup。
●一个布尔值,表示是否被应用的布局同ViewGroup(第二个参数)绑定在一起。
(如果系统已经将布局插入到了container中,改值为false,如果传true值,会造成在最终布局中多了一个冗余的viewgroup)
把Fragment加入activity
通常,一个Fragment组成它所在activity的UI的一部分,这里有两种把Fragment添加入activity布局中。
●在activity的布局文件中声明Fragment
这种情况下,你可以把Fragment当做一个view一样指定布局的属性。
例如,下例中的activity中有两个Fragment:
<
?
xmlversion="
1.0"
encoding="
utf-8"
>
LinearLayoutxmlns:
android="
android:
orientation="
horizontal"
layout_width="
match_parent"
layout_height="
<
fragmentandroid:
name="
com.example.news.ArticleListFragment"
id="
@+id/list"
layout_weight="
1"
0dp"
/>
com.example.news.ArticleReaderFragment"
@+id/viewer"
2"
/LinearLayout>
元素中的android:
name属性指定了在布局中需要初始化的Fragment类。
当系统创建这种activity布局时,布局中的每个Fragment都会进行实例化,每个Fragment都会调用onCreateView(),<
所在的那个view作为该回调方法的返回值。
每个Fragment都需要一个唯一的标示,当activity恢复的时候,系统可以使用该标示恢复Fragment(当执行事务的时候,也需要捕获该Fragment),有三种给出FragmentID的方法:
⏹用android:
id属性提供唯一的ID
tag属性提供唯一的字符串
⏹如果你两种方式都没有,系统使用容器view的id
●或者,通过编程将Fragment加入存在的ViewGroup
当你的activity运行的时候,你可以将Fragment添加到你的activity布局中。
你需要指定该Fragment要放入的ViewGroup。
为了在activity中执行一些Fragment事务(如:
添加、移除、替换等),你必须使用FragmentTransaction中的API。
通过如下模式从你的activity中来获取FragmentTransaction的实例:
FragmentManagerfragmentManager=getFragmentManager()
FragmentTransactionfragmentTransaction=fragmentManager.beginTransaction();
然后,使用add()方法进行Fragment的添加,指定要添加的Fragment及要加入到哪个view:
ExampleFragmentfragment=newExampleFragment();
fragmentTransaction.add(R.id.fragment_container,fragment);
fragmentTmit();
传递给add()方法的第一个参数,是要加入到的ViewGroup,该ViewGroup通过资源ID来指定,第二个参数指定被加入的Fragment。
一旦你通过FragmentTransaction来执行上面的事务的时候,你必须调用commit()来提交改变以生效。
添加没有UI的Fragment
上例在activity中添加具有UI的Fragment,然而,你也可以添加一个Fragment,为activity提供后台行为,而不提供UI。
为了添加没有UI的Fragment,在activity中使用add(Fragment,String)来添加Fragment(使用唯一的tag字符串,而不是view的ID)。
这就添加了Fragment,但没有加入activity的布局,也不会调用onCreateView()。
因此,你不需要实现该方法。
提供一个字符串tag并不仅仅针对没有UI的Fragment,对有UI的Fragment也可以提供字符串tag。
但是如果Fragment没有UI,则只能使用字符串tag来标示该Fragment。
如果你在activity中获取该Fragment,你需要使用findFragmentByTag()。
管理Fragment
为了管理你的activity中的Fragment,你需要使用FragmentManager。
在你的activity中调用getFragmentManager()来获取FragmentManager。
你可以用FragmentManager来做下面的事情:
●通过findFragmentById()(有UI的Fragment)或者findFragmentByTag()(有也可能没有UI的Fragment),获得activity中的Fragment。
●使用popBackStack()把Fragment从back栈中弹出(模拟用户的Back命令)
●使用addOnBackStackChangedListener()设置对back栈发生改变的事件监听器。
执行Fragment事务
在activity中使用Fragment的一个很大的特征就是可以使用它们进行添加、移除、替换及执行其他的动作。
你提交给activity的变化集称为一个事务,你可以使用FragmentTransaction中的API来执行。
你可以把每个事务都保存在activity所管理的back栈中,从而用户可以向后回撤。
示例代码如下:
FragmentManagerfragmentManager=getFragmentManager();
每个事务就是你在同时执行的变化集。
你可以通过使用add()、remove()及replace()方法设置所有的你要执行的变化集。
再调用commit()来将事务应用到activity。
在你调用commit()以前,你可能需要调用addToBackStack(),来将Fragment事务添加到back栈。
这个back栈有activity管理,允许用户按back按钮回到前一个Fragment状态。
下例把一个Fragment替换成另一个Fragment,并在back栈中保存前一个状态:
//Createnewfragmentandtransaction
FragmentnewFragment=newExampleFragment();
FragmentTransactiontransaction=getFragmentManager().beginTransaction();
//Replacewhateverisinthefragment_containerviewwiththisfragment,
//andaddthetransactiontothebackstack
transaction.replace(R.id.fragment_container,newFragment);
transaction.addToBackStack(null);
//Committhetransaction
mit();
在这个例子,newFragment替换掉由R.id.fragment_container所标示的布局容器中的任何Fragment。
通过调用addToBackStack(),该替换事务被保存在back栈中,因此用户可以按back按钮回撤到以前的Fragment。
如果你把多个变化加入到了事务并调用了addToBackStack(),在你调用commit()之前的所有变化都被作为一个事务保存在back栈中,一旦按下back按钮这些改变都会回撤。
在FragmentTransaction中添加的改变顺序无关紧要,除了:
●你必须在最后调用commit()
●如果你一个在同一个容器中添加了多个Fragment,加入的顺序就决定了view层中的现实顺序。
如果当你执行事务来移除一个Fragment,而你没有调用addToBackStack(),当提交事务的时候,该Fragment会被销毁,用户就不能回撤到前一个状态了。
反之,如果在移除Fragment的时候,你调用了addToBackStack()这个方法,那么Fragment会停止,当用户回撤的时候,该Fragment会恢复运行。
对commit()的调用,并不会立即执行事务,该事务会在activity的UI线程中等待调度。
如果需要的话,你可以在你的UI线程中调用executePendingTransaction()方法来立刻执行commit()提交的事务。
通常没必要这么做,除非在其他线程的中工作依赖于这个事务。
对于activity的状态保存(当用户离开activity的时候,调用onSaveInstanceState()),必须在commit()之后进行,如果在commit之前保存状态的话,会抛出异常。
这是因为在commit之前保存状态,事务不会被记录,从用户角度来看,事务就像丢失了。
如果你允许这么做的话,需要使用commitAllowingStateLoss()。
同activity通讯
尽管一个Fragment实现为独立于activity的对象,并且能被多个activity所使用,一个给定的Fragment实例被直接绑定在包含它的那个activity中。
特别地,Fragment可以通过getActivity()获取activity的实例,并执行诸如获取activity布局中视图的任务:
ViewlistView=getActivity().findViewById(R.id.list);
同样,你的activity可以通过FragmentManager中的findFragmentById()或者findFragmentByTag()方法来获取Fragment的引用,从而调用Fragment中的方法。
ExampleFragmentfragment=(ExampleFragment)getFragmentManager().findFragmentById(R.id.example_fragment);
创建activity的事件回调
在某些情况下,你可能需要一个Fragment来同activity共享事件。
一个好的办法是在Fragment中定义一个回调接口,并要求它的宿主activity实现它。
当activity通过接口收到了一个回调,在需要的时候,可以将信息同布局中其他Fragment分享信息。
例如,如果一个新闻app的一个activity中有两个Fragment,一个显示文章列表(FragmentA),一个显示文章内容(FragmentB),那么FragmentA必须告诉activity什么时候一个表项被选中了,这样activity会告诉FragmentB显示文章。
下面的例子中,在FragmentA中声明了一个OnArticleSelectedListener接口:
publicstaticclassFragmentAextendsListFragment{
...
//ContainerActivitymustimplementthisinterface
publicinterfaceOnArticleSelectedListener{
publicvoidonArticleSelected(UriarticleUri);
然后包含该Fragment的activity需要实现OnArticleSelectedListener,并复写onArticleSelected()来通知FragmentB来自FragmentA中的事件。
为确保宿主activity实现了这个接口,在FragmentA中的onAttach()回调方法(当将Fragment加入activity的时候会执行)实例化通过cast传递给onAttach()的activity为一个OnArticleSelectedListener实例:
OnArticleSelectedListenermListener;
publicvoidonAttach(Activityactivity){
super.onAttach(activity);
try{
mListener=(OnArticleSelectedListener)activity;
}catch(ClassCastExceptione){
thrownewClassCastException(activity.toString()+"
mustimplementOnArticleSelectedListener"
);