Fragment学习笔记

Fragment如果翻译成中文就是碎片,感觉还是不翻译直接用Fragment来表述更好些,它是Android3.0(API level 11)引入的,主要是为了适应大屏幕手机和平板电脑开发的,Fragment有自己的生命周期,一个Activity可以引入多个Fragment,它的使用就跟Web开发中Ajax的使用一样,方面局部刷新界面,极大得提高了用户的体验效果。

fragment_framework

上面这个应用主框架,现在看到的所有的交互页面都是在一个Activity中进行的,那么我们看到的所有功能页面现在都是用Fragment来完成的,这种交互设计也是现在Android市场上主流的界面设计风格。

本篇文章主要涉及Fragment的创建方式与生命周期、Fragment与Activity之间数据传递,Fragment与ViewPager以及ActionBar的结合使用在本篇文章中暂不涉及,以后再单独另写一篇笔记。

Fragment的创建方式

由于Fragment是在Android3.0才引入的,所以如果我们的应用还要兼容3.0之前的版本的话,我们可以使用support v4包。

方式一:直接布局在xml文件中

Android在写xml布局文件的时候我么可以拖拽某个控件直接到布局文件中,同样Fragment也同样可以拖拽。

add_fragment

在弹出窗口中选择相应的Fragment放入到布局中。

在生成的布局中我们可以看到android:name属性对应的是全类名(包名+类名)。

每一个片段需要在系统中有一个唯一的标识用以在活动重启时还原该Fragment(并且用于获取该Fragment以执行如移除该Fragment之类的操作)。有三种方式提供一个片段的ID:

  • 为android:id属性提供唯一的ID。
  • 为android:tag属性提供唯一的字符串。
  • 如果没有提供以上两种标识,系统将使用其容器视图的ID。

方式二:直接在Activity新建

在Activity中新建一个Fragment并把它加入到布局文件中,一般情况下每一个Fragment都应当在布局视图中,但是在Fragment的相关操作中,又引入了事务,就如同数据库中操作一样,每次对Fragment的操作都伴随着事务的开始(beginTransaction)与提交(commit),针对这一点我也想了很长时间,也不晓得这中想法是否正确,就如同在操作数据库一样,如果我们不添加相应的事务操作,我们知道Fragment的引入是为了适应大屏幕的开发,大屏幕开发中会有各种不同模块,对于每一个模块的更新操作,都有可能异步去请求网络数据,对于每一个操作线程耗时的多少我们是无法预知的,如果两个操作同时对同一个视图下的Fragment进行数据更新,就很有可能产生不可预知的结果,为了消除这种操作带来的紊乱现象,介入了事务来管理Fragment,这样每一次的操作行为都是一个不可分割的原子操作,每一次对Fragment的操作都必须是顺序执行完毕才能再次执行下次操作,保证了操作的完整性和稳定性。

FragmentManager

FragmentManager见名识意就是Fragment管理者,比较常用的方法:

  • beginTransaction():开启一个事务;
  • addOnBackStackChangedListener(OnBackStackChangedListener listener):返回键时回调函数;
  • findFragmentById (int id):根据id查找返回一个Fragment, 适用于在布局中提供了UI的Fragment;
  • findFragmentByTag (String tag):根据标签名查找返回一个Fragment,对于提供或没有提供UI的Fragment都适用;
  • popBackStack():将片段从返回栈中弹出(模拟一次用户按下BACK键的指令)

FragmentTransaction

FragmentTransaction提供了各种对Fragment的操作,每执行一次事务都代表了对Fragment执行了一次操作。比较常见的更新Fragment的操作有show、hide、add、remove、replace。
在这里重点讲的就是addToBackStack;

addToBackStack(String name):name是可选值,这个操作是将一次事务操作放入回退栈,如果在平板电脑中操作复杂界面,就如同在浏览器中点击回退按钮一样,只要页面没有被系统回收,总会返回当前操作的上一次操作。该方法仅仅是将一次事务操作放入回退栈中,而不是将某个特定Fragment放入回退栈。

遇到上面这种情况,如果我们点击回退,则会销毁当前的fragment01、fragment02两个Fragment,因为这两个Fragment是在同一个事务中进行操作的。

对于每一个Fragment在执行commit之前都可以执行一次动画,记住一点就是commit执行后并没有立即执行事务操作,它只是通知UI主线程可以调度这次事务。如有必要,可以在UI线程中调用executePendingTransactions()来立即执行由commit()提交的事务。

Fragment生命周期

我们知道Fragment是嵌套在Activity中的,因此它的生命周期与Activity息息相关。

activity_fragment_lifecycle

启动Activity

fragment_start_activity

销毁Activity

fragment_destory_activity

可以看出针对Activity状态的改变Fragment状态的改变就如果入栈出栈的操作,Activity启动的时候相应的Fragment状态总是后执行,当我们要销毁Activity时,Fragment的状态总是优先销毁。就如同进栈的时候Activity先进入,出栈的时候Activity后出,先进后出,恰好符合栈的操作。

有关生命周期更详细的介绍可以参考这篇博客http://leybreeze.com/blog/?p=902,事实上是一篇翻译的Fragment的api的文章。

Fragment与Activity数据交互

Activity主动传值到Fragment

Fragment主动传值到Activity

这中方式更简单了就是通过intent传值

Activity或Fragment获取值

例如获取Fragment中EditText中的值,或者Activity获取Fragment中EditText值:

在这里所讲的获取值指的是一个Fragment在某个Activity中的情况,也就是上面所讲的生命周期部分,Fragment的生命周期受Activity控制的情况,这也是最常见的传值方式。无论是Activity获取Fragment中的值还是Fragment获取Activity中的值,应该都不是太难,因为一个Fragment一定属于这个Activity了,所以在Fragment中可以通过getActivity()就获取到了Activity,再通过Activity中的UI控件或方法得到所要的值都是一件很简单的事。

同样的道理,Activity获取某一个Fragment中值也同上面说的一样,既然Activity已经有了这个Fragment的对象,想拿到你控件或方法值都轻而易举了。

回调函数传值

简单的举个例子,在Activity中获取Fragment中某个控件的值:

单例模式传值

这种方式这里就不多讲了,在Activity学习笔记这篇文章中已经介绍过了,就是通过一个单例对象先存入再获取值,这种方式也很便利。

结束语

因为Fragment相关知识点相当多,而且应用也非常广泛,特别是与ViewPager结合使用,这当中又涉及到了FragmentPagerAdapter以及FragmentStatePagerAdapter两个相当关键的类,同时既然Fragment生命周期不用开发者手动管理,那么这当中涉及到了状态保存现场还原,如在ViewPager划过当前页之后再次返回数据的处理等等,这当中好多细节性的东西我也是看着明白一写就又糊涂了,这里是一块硬骨头,需要花些时日好好啃一啃,就写到这里了,以后再将剩下的这些知识点一点一点深入下来。

本文地址www.sunnyang.com/260.html

7 comments

发表评论