1、Fragment概述
Fragment是Android3.0后引入的一个新的API,他出现的初衷是为了适应大屏幕的平板电脑, 当然现在他仍然是平板APP UI设计的宠儿,而且我们普通手机开发也会加入这个Fragment, 我们可以把他看成一个小型的Activity,又称Activity片段!想想,如果一个很大的界面,我们 就一个布局,写起界面来会有多麻烦,而且如果组件多的话是管理起来也很麻烦!而使用Fragment我们可以把屏幕划分成几块,然后进行分组,进行一个模块化的管理!从而可以更加方便的在 运行过程中动态地更新Activity的用户界面!另外Fragment并不能单独使用,他需要嵌套在Activity中使用,尽管他拥有自己的生命周期,但是还是会受到宿主Activity的生命周期的影响,比如Activity被destory销毁了,他也会跟着销毁!
2、Fragment生命周期
①Activity加载Fragment的时候,依次调用下面的方法: onAttach -> onCreate -> onCreateView ->onActivityCreated -> onStart ->onResume
②当我们弄出一个悬浮的对话框风格的Activity,或者其他,就是让Fragment所在的Activity可见,但不获得焦点onPause
③当对话框关闭,Activity又获得了焦点: onResume
④当我们替换Fragment,并调用addToBackStack()将他添加到Back栈中 onPause -> onStop -> onDestoryView !!注意,此时的Fragment还没有被销毁哦!!!
⑤当我们按下键盘的回退键,Fragment会再次显示出来: onCreateView -> onActivityCreated -> onStart -> onResume
⑥如果我们替换后,在事务commit之前没有调用addToBackStack()方法将Fragment添加到back栈中的话;又或者退出了Activity的话,那么Fragment将会被完全结束, Fragment会进入销毁状态 onPause -> onStop ->onDestoryView -> onDestory -> onDetach
3、Fragment要点
3.1 特点
· 3.0版本后引入,即minSdk要大于11
· Fragment需要嵌套在Activity中使用,当然也可以嵌套到另外一个Fragment中,但这个被嵌套 的Fragment也是需要嵌套在Activity中的,间接地说,Fragment还是需要嵌套在Activity中!!受寄主Activity的生命周期影响,当然他也有自己的生命周期!另外不建议在Fragment里面 嵌套Fragment因为嵌套在里面的Fragment生命周期不可控!!!
· 官方文档说创建Fragment时至少需要实现三个方法:onCreate( ),onCreateView( ),OnPause( );不过貌似只写一个onCreateView也是可以的...
· Fragment的生命周期和Activity有点类似:三种状态:
Resumed:在允许中的Fragment可见
Paused:所在Activity可见,但是得不到焦点
Stoped: ①调用addToBackStack(),Fragment被添加到Bcak栈②该Activity转向后台,或者该Fragment被替换/删除
ps:停止状态的fragment仍然活着(所有状态和成员信息被系统保持着),然而,它对用户 不再可见,并且如果activity被干掉,他也会被干掉.
3.2 子类
· 对话框:DialogFragment
· 列表:ListFragment
· 选项设置:PreferenceFragment
· WebView界面:WebViewFragment
3.3 包
我们到底是使用android.app下的Fragment还是用的android.support.v4.app包下 的Fragment呢?其实都可以,前面说过Fragment是Android 3.0(API 11)后引入的,那么如果开发的app需要 在3.0以下的版本运行呢?比如还有一点点市场份额的2.3!于是乎,v4包就这样应运而生了,而最低可以兼容到1.6版本!至于使用哪个包看你的需求了,现在3.0下手机市场份额其实已经不多了,随街都是4.0以上的,6.0十月份都出了,你说呢...所以这个时候,你可以直接使用app包下的Fragment然后调用相关的方法,通常都是不会有什么问题的;如果你Fragment用了app包的, FragmentManager和FragmentTransaction都需要是app包的!要么用全部用app,要么全部用v4,不然可是会报错的哦!当然如果你要自己的app对于低版本的手机也兼容的话,那么就可以选择用v4包!
·如果你使用了v4包下的Fragment,那么所在的那个Activity就要继承FragmentActivity哦!案例:今天在xml文件中静态地载入fragment,然后重写了Fragment,但是在加载Activity的时候就报错了, 大概的提示就是Fragment错误还是找不到什么的,name属性改了几次还是错!最后才发现是用了v4的包的缘故,只需让自己的Activity改成FragmentActivity即可!
4、创建Fragment
4.1静态加载
4.2动态加载
4.3Fragment的管理
4.4Fragment与Activity交互
Fragment与Fragment之间的数据互传
其实这很简单,找到要接受数据的fragment对象,直接调用setArguments传数据进去就可以了 通常的话是replace时,即fragment跳转的时候传数据的,那么只需要在初始化要跳转的Fragment后调用他的setArguments方法传入数据即可!
如果是两个Fragment需要即时传数据,而非跳转的话,就需要先在Activity获得f1传过来的数据,再传到f2了,就是以Activity为媒介~
5、Fragment注意事项
(1)使用FragmentPagerAdapter+ViewPager的注意事项
使用FragmentPagerAdapter+ViewPager时,切换回上一个Fragment页面时(已经初始化完毕),不会回调任何生命周期方法以及onHiddenChanged(),只有setUserVisibleHint(boolean isVisibleToUser)会被回调,所以如果你想进行一些懒加载,需要在这里处理。
在给ViewPager绑定FragmentPagerAdapter时,new FragmentPagerAdapter(fragmentManager)的FragmentManager,一定要保证正确,如果ViewPager是Activity内的控件,则传递getSupportFragmentManager(),如果是Fragment的控件中,则应该传递getChildFragmentManager()。只要记住ViewPager内的Fragments是当前组件的子Fragment这个原则即可。
你不需要考虑在“内存重启”的情况下,去恢复的Fragments的问题,因为FragmentPagerAdapter已经帮我们处理啦。
(2)是使用单Activity+多Fragment的架构,还是多模块Activity+多Fragment的架构?
单Activity+多Fragment:一个app仅有一个Activity,界面皆是Frament,Activity作为app容器使用。
优点:性能高,速度最快。参考:新版知乎 、google系app
缺点:逻辑比较复杂,尤其当Fragment之间联动较多或者嵌套较深时,比较复杂。
多模块Activity+多Fragment:一个模块用一个Activity,比如
1、登录注册流程:
LoginActivity + 登录Fragment +注册Fragment +填写信息Fragment+ 忘记密码Fragment
2、或者常见的数据展示流程:
DataActivity + 数据列表Fragment +数据详情Fragment+ ...
优点:速度快,相比较单Activity+多Fragment,更易维护。
多模块Activity+多Fragment是最合适的架构,开发起来不是很复杂,app的性能又很高效。(出自http://www.jianshu.com/p/fd71d65f0ec6)
1、对Fragment传递数据,建议使用setArguments(Bundle args),而后在onCreate中使用getArguments()取出,在 “内存重启”前,系统会帮你保存数据,不会造成数据的丢失。和Activity的Intent恢复机制类似。
2、使用newInstance(参数) 创建Fragment对象,优点是调用者只需要关系传递的哪些数据,而无需关心传递数据的Key是什么。
3、如果你需要在Fragment中用到宿主Activity对象,建议在你的基类Fragment定义一个Activity的全局变量,在onAttach中初始化,这不是最好的解决办法,但这可以有效避免一些意外Crash。
1、区别
show(),hide()最终是让Fragment的View setVisibility(true还是false),不会调用生命周期;
replace()的话会销毁视图,即调用onDestoryView、onCreateView等一系列生命周期;
add()和 replace()不要在同一个阶级的FragmentManager里混搭使用。
2、使用场景
如果你有一个很高的概率会再次使用当前的Fragment,建议使用show(),hide(),可以提高性能。
在我使用Fragment过程中,大部分情况下都是用show(),hide(),而不是replace()。
注意:如果你的app有大量图片,这时更好的方式可能是replace,配合你的图片框架在Fragment视图销毁时,回收其图片所占的内存。
3、onHiddenChanged的回调时机
当使用add()+show(),hide()跳转新的Fragment时,旧的Fragment回调onHiddenChanged(),不会回调onStop()等生命周期方法,而新的Fragment在创建时是不会回调onHiddenChanged(),这点要切记。
4、Fragment重叠问题
使用show(),hide()带来的一个问题就是,如果你不做任何额外处理,在“内存重启”后,Fragment会重叠;(该BUG在support-v4 24.0.0+以上 官方已修复)