Android Fragment 生命周期及其正确使用(建议使用自定义View替换Fragment)
使用Fragment 官方例子中显示:
例如:一个学生Fragment,需要传入studentId,进行http请求显示,那么setArguments后防止杀掉Fragment后,参数为0,显示不了数据。
public static StudentFragment newInstance(int studentId){
StudentFragment fragment = new StudentFragment();
Bundle bundle = new Bundle();
bundle.putInt("student_id", studentId);
fragment.setArguments(bundle);
return fragment;
}
setArguments:
private int mStudentId = 0; @Override
public void setArguments(Bundle args) {
super.setArguments(args); mStudentId = args.getInt("student_id", 0);
}
那么app在杀死后,回到这个Fragment 时,会在onCreateView时,进行获取参数,获取正确的页面数据,不然有可能会因为null,而崩毁。
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mStudentId = getArguments().getInt("student_id", 0); return super.onCreateView(inflater, container, savedInstanceState);
}
Fragment:( Fragment就相当于一个有生命周期的View,它的生命周期被所在的Activity的生命周期管理 )

生命周期回调说明:
onAttach(Activity)
当Fragment与Activity发生关联时调用。
onCreateView(LayoutInflater, ViewGroup,Bundle)
创建该Fragment的视图
onActivityCreated(Bundle)
当Activity的onCreate方法返回时调用
onDestoryView()
与onCreateView想对应,当该Fragment的视图被移除时调用
onDetach()
与onAttach相对应,当Fragment与Activity关联被取消时调用
与Activity 依赖关系:

与ViewPager 的关系:
(1)setOffscreenPageLimit
// 预加载页面的数量
viewPager.setOffscreenPageLimit(2);
知道ViewPager会有预加载的特性,我以为Fragment_1会从 1 onAttach() 开始直到 6 onResume()后,Fragment_2才会开始从 1onAttach()开始,到了3 onCreateView()会停止。然而,并不是预想的这样。
首先,Fragment_1 经历 1_onAttach() 和 2_onCreate() 后, Fragment_2也开始走了 1_onAttach()和 2_onCreate()方法。
接着,Fragment_1依次经历 3_onCreateView(), 4_onCreateActivity(),5 _onStart ,6_onResume()。此时,Fragment_1获得焦点,已经展示在手机屏幕。Fragment_2也接着从 3_onCreate()开始直到也执行到 6_onResume()方法。疑问就在这,我个人感觉既然Fragment_2没有在屏幕显示,就不会执行到 6_onResume()方法,然而Log信息却显示执行到了 6_onResume()。这里记录一下。
多了Fragment_3的Log信息,而且走的方法和Frgment_1和2是一样的。后面的情况的Log信息便不再贴出来了,本质是一样的,只是多预加载了一个Fragment。但此时ViewPager依然只是保留3个Fragment的信息。当滑到Fragment_4的时候,Fragment_1走了7_onPause(),8_onStop(),9_onDestroyView()。Fragment_2,3,4则处于6_onResume()。
这个方法对Fragment生命周期方法的调用顺序上并没有什么影响,只是预加载的Fragment的数量又设置的limit参数决定。
(2)setUserVisibleHint
setUserVisibleHint()这个方法会在预加载Fragment时,会在Fragment的1_onAttach()前调用。此时,在setUserVisibleHint()里面调用也不用害怕空指针的问题,因为有3个前条件。当通过滑动ViewPger时,根据6.1知道,每次滑动都会调用setUserVisibleHint()这个方法,进行预加载后,当滑到Fragment_2,3,4时,就会调用里面的load()方法。
在Fragment的4_onCreateActivity()中调用load。我个人习惯把网络请求放在这个生命周期。在Fragment_1和点击Tab时,引起问题的原因就是setUserVisibleHint()先于1_onAttach()调用,不能满足前提条件中的isCreate,所以load方法不会被调用。而4_onCreateActivity()中会再次调用load()方法,此时还满足3个前提条件。这样,遗留的问题也解决了。ViewPager中Fragment延迟加载这个需求也可以实现了。如果此时Fragment中有一个轮播图的话,也可以通过getUserVisibleHint()这个方法来选择关闭轮播图线程的时机。
Fragment Api:
Fragment常用的三个类:
android.app.Fragment 主要用于定义Fragment
android.app.FragmentManager 主要用于在Activity中操作Fragment
android.app.FragmentTransaction 保证一些列Fragment操作的原子性
主要的操作都是FragmentTransaction的方法:
// v4包中,getSupportFragmentManager
FragmentManager fm = getFragmentManager();
// 开启一个事务 (主要的操作都是FragmentTransaction的方法)
FragmentTransaction transaction = fm.benginTransatcion(); // 往Activity中添加一个Fragment
transaction.add(Fragment fragment);
// 从Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈(回退栈后面会详细说),这个Fragment实例将会被销毁。
transaction.remove(Fragment fragment);
// 使用另一个Fragment替换当前的,实际上就是remove()然后add()的合体
transaction.replace(R.id.XXX, Fragment fragment);
// 隐藏当前的Fragment,仅仅是设为不可见,并不会销毁
transaction.hide(Fragment fragment);
// 显示之前隐藏的Fragment
transaction.show(Fragment fragment);
//提交一个事务
transatcion.commit();
// 会将view从UI中移除,和remove()不同,此时fragment的状态依然由FragmentManager维护。
detach()
// 重建view视图,附加到UI上并显示。
attach();
判断什么时候该使用什么方法:
(1)希望保留用户操作的面板,可以使用hide和show。
(2)不希望保留用户操作,可以使用remove(),然后add();或者直接使用replace(),效果相同。
(3)remove会销毁整个Fragment实例,而detach则只是销毁其视图结构,实例并不会被销毁。
(4)当前Activity一直存在,那么在不希望保留用户操作的时候,可以优先使用detach。
参考地址:Android Fragment 真正的完全解析(上) Android Fragment 真正的完全解析(下)
对于用法:
(1)getActivity() 方法空指针问题:
onAttach(Activity activity)里赋值,使用mActivity代替getActivity(),保证Fragment即使在onDetach后,仍持有Activity的引用(有引起内存泄露的风险,但是异步任务没停止的情况下,本身就可能已内存泄漏,相比Crash,这种做法“安全”些),即:protected Activity mActivity; /**
* API低于 23 的版本中不会去调用后者,只会去调用onAttach(Activity)
*/
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.mActivity = activity;
} /**
* 如果用了support 23的库,上面的方法会提示过时,且不会被调用,可以用下面的方法代替
*/
@Override
public void onAttach(Context context) {
super.onAttach(context);
this.mActivity = (Activity) context;
}
如不需要使用getActivity():
/*
* onAttach(Context) is not called on pre API 23 versions of Android and onAttach(Activity) is deprecated
* Use onAttachToContext instead
*/
@TargetApi(23)
@Override
public void onAttach(Context context) {
super.onAttach(context);
onAttachToContext(context);
} /*
* Deprecated on API 23
* Use onAttachToContext instead
*/
@SuppressWarnings("deprecation")
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
onAttachToContext(activity);
}
} /*
* Called when the fragment attaches to the context
*/
protected void onAttachToContext(Context context) {
//do something
}
(2)未必靠谱的出栈方法remove()
如果你想让某一个Fragment出栈,使用remove()在加入回退栈时并不靠谱。
如果你在add的同时将Fragment加入回退栈:addToBackStack(name)的情况下,它并不能真正将Fragment从栈内移除,如果你在2秒后(确保Fragment事务已经完成)打印getSupportFragmentManager().getFragments(),会发现该Fragment依然存在,并且依然可以返回到被remove的Fragment,而且是空白页面。
如果你没有将Fragment加入回退栈,remove方法可以正常出栈。
如果你加入了回退栈,popBackStack()系列方法才能真正出栈,这也就引入下一个深坑,popBackStack(String tag,int flags)等系列方法的BUG。
(3)Fragment转场动画
如果你的Fragment没有转场动画,或者使用setCustomAnimations(enter, exit)的话。
getFragmentManager().beginTransaction().setCustomAnimations(enter, exit);
// 如果通过tag/id同时出栈多个Fragment的情况时,
// 请谨慎使用.setCustomAnimations(enter, exit, popEnter, popExit)
// 在support-25.4.0之前出栈多Fragment时,伴随出栈动画,会在某些情况下发生异常
// 你需要搭配Fragment的onCreateAnimation()临时取消出栈动画,或者延迟一个动画时间再执行一次上面提到的Hack方法,排序
请使用.setCustomAnimations(enter, exit, popEnter, popExit),这个方法的第1个参数对应进栈动画,第4个参数对应出栈动画,所以是.setCustomAnimations(进栈动画, exit, popEnter, 出栈动画)
如果想让出栈动画运作正常的话,需要使用Fragment的onCreateAnimation中控制动画:
@Override
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
// 此处设置动画
}
pop多个Fragment时转场动画 带来的问题:
在使用 pop(tag/id)出栈多个Fragment的这种情况下,将转场动画临时取消或者延迟一个动画的时间再去执行其他事务;
原因在于这种情景下,可能会导致栈内顺序错乱(上文有提到),同时如果发生“内存重启”后,因为Fragment转场动画没结束时再执行其他方法,会导致Fragment状态不会被FragmentManager正常保存下来。
2、进入新的Fragment并立刻关闭当前Fragment 时的一些问题
(1)如果你想从当前Fragment进入一个新的Fragment,并且同时要关闭当前Fragment。由于数据结构是栈,所以正确做法是先pop,再add,但是转场动画会有覆盖的不正常现象,你需要特殊处理,不然会闪屏!
如果你遇到Fragment的mNextAnim空指针的异常(通常是在你的Fragment被重启的情况下),那么你首先需要检查是否操作的Fragment是否为null;其次在你的Fragment转场动画还没结束时,你是否就执行了其他事务等方法;解决思路就是延迟一个动画时间再执行事务,或者临时将该Fragment设为无动画
对于一些操作,Fragment发生的生命周期变化:
切换到该Fragment:onAttach() -> onCreate() -> onCreateView() -> onActivityCreated() -> onStart() -> onResume()
屏幕灭掉或者回到桌面(Home): onPause() -> onSaveInstanceState() -> onStop()
屏幕解锁或者重新回到应用: onStart() -> onResume()
切换到其他Fragment: onPause() -> onStop() -> onDestroyView()
切换回本身的Fragment: onCreateView() -> onActivityCreated() -> onStart() -> onResume()
退出应用:onPause() -> onStop() -> onDestroyView() -> onDestroy() -> onDetach()
参考:
Android Fragment 生命周期及其正确使用(建议使用自定义View替换Fragment)的更多相关文章
- Android Fragment 生命周期及其API使用(建议使用自定义View替换Fragment)
我为什么不主张使用Fragment Fragment:( Fragment就相当于一个有生命周期的View,它的生命周期被所在的Activity的生命周期管理 ) 生命周期回调说明: onAttach ...
- Android零基础入门第86节:探究Fragment生命周期
一个Activity可以同时组合多个Fragment,一个Fragment也可被多个Activity 复用.Fragment可以响应自己的输入事件,并拥有自己的生命周期,但它们的生命周期直接被其所属的 ...
- 重温Android和Fragment生命周期
重温下Android和Fragment生命周期,理解生命周期方法的作用,什么时候调用,可以做一些什么操作. 1.Android生命周期 1.1 生命周期图 1.2 生命周期函数说明 onCreate: ...
- Android Activity生命周期以及Fragment生命周期的区别与分析
Android Fragment生命周期图: Activity生命周期图: 对照图: Fragment生命周期分析: 1. 当一个fragment被创建的时候,它会经历以下状态. onAttach() ...
- 【Android基础】Fragment 详解之Fragment生命周期
上一篇文章简单介绍了一下Fragment,这一篇文章会详细的说一下Fragment的生命周期和创建一个用户界面. Fragment的主要功能就是创建一个View,并且有一个生命周期来管理这个View的 ...
- Android中Fragment生命周期和基本用法
1.基本概念 1. Fragment是什么? Fragment是可以让你的app纵享丝滑的设计,如果你的app想在现在基础上性能大幅度提高,并且占用内存降低,同样的界面Activity占用内存比Fra ...
- Android之Fragment学习笔记②(Fragment生命周期)
一. Fragment生命周期图 二.Fragment生命周期方法介绍 Fragment的生命周期和activity生命周期很像,其生 ...
- 【Android开发】之Fragment生命周期
上一篇博客我们讲到了,Fragment的基本使用,相信大家都已经了解怎么去使用了.如果还有不懂得同学可以去看一下,传送门.现在我们来讲解一下Fragment的生命周期. 一.Fragment的事务 再 ...
- 【Android归纳】Fragment生命周期-基于实验的最新总结
如今非常多应用的开发都是基于FragmentActivity中嵌套Fragment进行开发的,所以,假设我们可以清晰地知道他们的生命周期,那么会使我们的开发变的easy. 对于Activity的生命周 ...
随机推荐
- 使用PowerDesigner 15对现有数据库进行生成图表结构
PowerDesigner的安装和基本使用,我就不阐述了.大家可以到这里看看:http://www.blogjava.net/wangdetian168/archive/2011/04/07/Powe ...
- Linux内核入门到放弃-无持久存储的文件系统-《深入Linux内核架构》笔记
proc文件系统 proc文件系统是一种虚拟的文件系统,其信息不能从块设备读取.只有在读取文件内容时,才动态生成相应的信息. /proc的内容 内存管理 系统进程的特征数据 文件系统 设备驱动程序 系 ...
- xgboost 参数调优指南
一.XGBoost的优势 XGBoost算法可以给预测模型带来能力的提升.当我对它的表现有更多了解的时候,当我对它的高准确率背后的原理有更多了解的时候,我发现它具有很多优势: 1 正则化 标准GBDT ...
- Educational Codeforces Round 62 (Rated for Div. 2) - C Playlist
当时题意看错了...不过大致思路是对的,唯一没有想到的就是用优先队列搞这个东西,真是不该啊... 题意大概就是,有N首歌,N首歌有两个东西,一个是长度Ti,一个是美丽值Bi,你最多可以选择K首歌, 这 ...
- vue中使用LESS、SASS、stylus
less的使用 npm install less less-loader --save 修改webpack.config.js文件.vue.cli 搭建项目可跳过此步 { test: /\.less$ ...
- windows服务器nginx+php启动开源ecshop
1,下载php,nginx,ECShop源码 2,解压php到指定目录(如:C:\php-7.2.6) 2.1,找到指定目录下文件php.ini-development复制重命名为php.ini 2. ...
- js02-常用流程控制语句
1.if语句 语法:if(条件){ 条件成立时执行 }else{ 条件不成立执行 } 例 var ji = 20; if(ji>=20){ console.log('恭喜你,吃鸡成功,大吉大利' ...
- Python抓取天气信息并存储原来这么简单
我们计划抓取的数据:杭州的天气信息 实现数据抓取的逻辑:使用python 请求 URL,会返回对应的 HTML 信息,我们解析 html,获得自己需要的数据.(很简单的逻辑) 第一步:创建 Pytho ...
- 4.ansible的delegate_to
完成发布流程如下 first 修改nginx 配置文件下线 web1-2 使用 delegate_to 将默认hosts指定为 nginx主机 使用remote_user 将用户 锁定为 root s ...
- SQL 中使用 WITH AS 提高性能
一.WITH AS的含义WITH AS短语,也叫做子查询部分(subquery factoring),可以让你做很多事情,定义一个SQL片断,该SQL片断会被整个SQL语句所用到.有的时候,是为了让S ...