版权声明:本文为博主原创文章,未经博主允许不得转载。

微博:厉圣杰

源码:AndroidDemo/Fragment

文中如有纰漏,欢迎大家留言指出。

Fragment 是在 Android 3.0 中引入,用于解决不同屏幕分辨率的设备上 UI 显示、交互的问题。Fragment 有自己的布局,有自己的生命周期,有自己的事件响应。

但 Fragment 又是依赖于 Activity 存在的,你可以把多个 Fragment 嵌入到一个 Activity 中或者多个 Activity 重用一个 Fragment。Activity 的生命周期直接影响 Fragment 的生命周期。所以要正确的使用 Fragment,首先必要从根本上了解 Fragment 的生命周期,俗话说:工欲善其事必先利其器

简单来说,Fragment 的生命周期可以用下图来表示:

是不是觉得这图看着很眼熟,没错,前面讲过 Fragment 是依赖于 Activity 存在的,所以 Fragment 的生命周期跟 Activity 的生命周期很相似。

下图很好的描述了 Fragment 与 Activity 生命周期的关系,请看图~

Fragment 的生命周期这样就讲完了?理论上来说,是的。我说楼主,你还真是浅谈别急,下面还有呢

上面只是展示了 Fragment 与 Activity 生命周期最基本的关系,如果通过 addToBackStack() 将 Fragment 放入回退栈,然后通过 popBackStack() 出栈,Fragment 的生命周期会如何变化呢?如果 Fragment 与 ViewPager 结合使用,Fragment 的生命周期又是如何?如果通过 hide()show() 方法来展示隐藏,这时 Fragment 的生命周期又会如何?

不急,先看思维导图中的问题,然后咱们就来研究一下上诉问题~

既然是 Fragment 的生命周期,那自然是少不了对 Fragment 生命周期的监测,怎么办?打 Log。

项目结构如下

本文涉及到的类主要集中在 lifecircle 包中及 LifeCircleFragment。代码已上传 AndroidDemo/Fragment ,这里贴出 LifeCircleFragment 的主要代码。

LifeCircleFragment.java

/**
* 测试 Fragment 生命周期,setUserVisibleHint 初始进来时只有默认 Tab
* Created by littlejie on 2016/12/30.
*/ public class LifeCircleFragment extends BaseFragment { private final String TAG = LifeCircleFragment.class.getSimpleName();
//截取 Fragment.toString() 方法中的标识数字
private final String ID = this.toString().substring(this.toString().indexOf("{") + 1, this.toString().length() - 1);
private TextView mTvContent; //默认 Title 值
private String mTitle = "Tab"; public static LifeCircleFragment newInstance(String title) {
Bundle args = new Bundle(); LifeCircleFragment fragment = new LifeCircleFragment();
args.putString(Constant.PARAM_TITLE, title);
fragment.setArguments(args);
return fragment;
} /**
* 当 Fragment 调用 hide() 、 show() 时回调
* @param hidden
*/
@Override
public void onHiddenChanged(boolean hidden) {
Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onHiddenChanged.hidden = " + hidden);
super.onHiddenChanged(hidden);
} /**
* 当 Fragment 与 ViewPager 结合使用时,切换 Pager 时回调
* @param isVisibleToUser
*/
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is setUserVisibleHint.isVisibleToUser = " + isVisibleToUser);
super.setUserVisibleHint(isVisibleToUser);
} /**
* Fragment 关联到 Activity 时回调
* 此时 Activity 已经与 Fragment 关联,通过 Context 向下转型,就可以与 Activity 通信
* 当然也可以使用 getActivity(),前提是这个 fragment 已经和宿主的 activity 关联,并且没有脱离
* onAttach 只调用一次。
*
* @param context
*/
@Override
public void onAttach(Context context) {
//由于 onCreate 是在 onAttach 后执行,故此时 mTitle 为空
Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onAttach.");
super.onAttach(context);
} /**
* 系统创建 Fragment 的时候回调,介于 onAttach() 和 onCreateView() 之间
* 一般用于初始化一些数据
* 值得注意的是,此时 Activity 还在创建中,因此不能在执行一些跟 Activity UI 相关的操作
* 否则,会出现一些难以预料的问题,比如:NullPointException
* 如果要对 Activity 上的 UI 进行操作,建议在 onActivityCreated() 中操作
*
* @param savedInstanceState
*/
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onCreate.");
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
if (getArguments() != null) {
mTitle = getArguments().getString(Constant.PARAM_TITLE);
}
//测试 onCreate() 是 Activity 的 UI 是否初始化完成
//if (getContext() instanceof LifeCircleActivity) {
//((LifeCircleActivity) getContext()).setActivityCreated("Fragment 进行 onCreate() 时 Activity UI 尚未初始化完成。"
// + "\n你看不到我,因为我已经变成异常抛出了。");
//}
} /**
* 创建 Fragment 需要显示的 View,默认返回 null。
* 当返回的 View 不为 null 时,View 被销毁时会调用 onDestroyView()
* 此处应该只进行布局的初始化,而不应该执行耗时操作,如网络请求、数据库读取
*
* @param inflater
* @param container
* @param savedInstanceState
* @return
*/
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onCreateView.");
return inflater.inflate(R.layout.fragment_life_circle, container, false);
} /**
* 该方法在 onCreateView() 之后会被立即执行
* 此时可以对 View 对象进行赋值,当然在 onCreateView() 中也可以执行
*
* @param view
* @param savedInstanceState
*/
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onViewCreated.");
super.onViewCreated(view, savedInstanceState);
mTvContent = (TextView) view.findViewById(R.id.tv_content);
mTvContent.setText(mTitle);
} /**
* 当 Activity 执行完 onCreate() 方法后调用
* 此时可以执行与 Activity 相关的 UI 操作
*
* @param savedInstanceState
*/
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onActivityCreated.");
super.onActivityCreated(savedInstanceState);
//测试 onCreate() 是 Activity 的 UI 是否初始化完成
if (getContext() instanceof SimpleLifeCircleActivity) {
((SimpleLifeCircleActivity) getContext()).setActivityCreated("Fragment 进行 onActivityCreated() 时 Activity UI 已初始化完成。"
+ "\n你能看到我。");
}
} @Override
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onViewStateRestored.");
super.onViewStateRestored(savedInstanceState);
} /*-----------跟 Activity 中对应方法类似-------------*/
@Override
public void onStart() {
Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onStart.");
super.onStart();
} @Override
public void onResume() {
Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onResume.");
super.onResume();
} @Override
public void onPause() {
Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onPause.");
super.onPause();
} @Override
public void onStop() {
Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onStop.");
super.onStop();
}
/*-----------跟 Activity 中对应方法类似-------------*/ /**
* 表示销毁 Fragment 相关联的 UI 布局,清除所有跟视图相关的资源。
* 不一定在 Activity 的 onDestroy() 方法中调用
* 如:Fragment 与 ViewPager 结合使用时
*
* @see com.littlejie.fragment.lifecircle.LifeCircleWithViewPagerActivity
*/
@Override
public void onDestroyView() {
Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onDestroyView.");
super.onDestroyView();
} /**
* 销毁 Fragment 对象的时候调用,一般是调用 Activity 的 onDestroy() 的时候执行
*/
@Override
public void onDestroy() {
//当调用 Activity 的 onDestroy() 时调用
Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onDestroy.");
super.onDestroy();
} /**
* 解除 Fragment 与 Activity 的关联
*/
@Override
public void onDetach() {
Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onDetach.");
super.onDetach();
} }

由于日志过多,这里不再展示,有兴趣的可自行下载 Demo 测试。这里简要总结下关于 Fragment 生命周期。

  1. 第一点很重要,最开始的两张图展示的 Fragment 与 Activity 的生命周期关系没毛病。
  2. onAttach()onCreate() 只在 Fragment 与 Activity 第一次关联时调用。
  3. onDestroy()onDetach() 只在 Fragment 的宿主 Activity 销毁时才会被调用。
  4. 根据前 3 点,将 Fragment 通过 addToBackStack() 只涉及 onCreateView()onDestroyView() 这之间的生命周期。add()replace() 不会对 Fragment 的生命周期产生影响,但 add() 方法会造成 Fragment 叠加显示。
  5. Fragment 与 ViewPager 结合使用时的生命周期与第 4 点相似。
  6. 通过 hide()show() 来隐藏、显示Fragment,此时 Fragment 只改变了可见性,并不涉及生命周期的改变
  7. 第 7 点与Fragment 和 Activity 的生命周期有关,即:不要在 Fragment 的 onCreate() 方法中操作宿主Activity 的 UI。因为你无法保证此时 宿主Activity 的 UI 已经完全初始化。PS:某些情况下是可以确保 宿主Activity 已经初始化完成的。

恩,的确算浅谈,给出了自认为正确的结论,欢迎各位前来打脸~

源码地址:AndroidDemo/Fragment。欢迎大家 Star 和 Fork。

浅谈 Fragment 生命周期的更多相关文章

  1. Fragment生命周期函数调用(ViewPager切换方式)

    在使用ViewPager时,Google亲爹为我们提供了多种PagerAdapter.其中,与Fragment相关的是FragmentPagerAdapter和FragmentStatePagerAd ...

  2. Android Fragment 生命周期及其API使用(建议使用自定义View替换Fragment)

    我为什么不主张使用Fragment Fragment:( Fragment就相当于一个有生命周期的View,它的生命周期被所在的Activity的生命周期管理 ) 生命周期回调说明: onAttach ...

  3. Android之Fragment学习笔记②(Fragment生命周期)

    一. Fragment生命周期图                                  二.Fragment生命周期方法介绍 Fragment的生命周期和activity生命周期很像,其生 ...

  4. Android Activity生命周期以及Fragment生命周期的区别与分析

    Android Fragment生命周期图: Activity生命周期图: 对照图: Fragment生命周期分析: 1. 当一个fragment被创建的时候,它会经历以下状态. onAttach() ...

  5. 从实践谈iOS生命周期

    从实践谈iOS生命周期 个人感觉生命周期无论在Android,还是iOS都是很重要的概念,因为在每个声明周期的状态下我们可以做很多预加载或者处理的操作.因此在这里主要总结下ViewController ...

  6. Fragment(四)Fragment生命周期分析(转)

    Fragment(四)Fragment生命周期分析 转载请注明:http://blog.csdn.net/liaoqianchuan00/article/details/24271607   例子一 ...

  7. Fragment生命周期与Fragment执行hide、show后的生命周期探讨

    一.Fragment 生命周期中的每个方法的意义与作用: 1.setUserVisibleHint()(此方法不属于生命周期方法):设置Fragment 用户可见或不可见时调用此方法,此方法在Frag ...

  8. Fragment生命周期以及使用时的小问题

    前言- 昨天在写UI的时候用到了FRAGMENT,发现自己对此还不是非常了解,借此机会记录一下 Fragment的生命周期- 官方生命周期图: Fragment每个生命周期方法的意义.作用- onVi ...

  9. Fragment 生命周期的详情

    Fragment每个生命周期方法的意义.作用(注意红色的不是生命周期方法):setUserVisibleHint():设置Fragment可见或者不可见时会调用此方法.在该方法里面可以通过调用getU ...

随机推荐

  1. Vue.js 和 MVVM 小细节

    MVVM 是Model-View-ViewModel 的缩写,它是一种基于前端开发的架构模式,其核心是提供对View 和 ViewModel 的双向数据绑定,这使得ViewModel 的状态改变可以自 ...

  2. CSS的未来

    仅供参考 前言 完成<CSS核心技术与实战>这本书,已有一个多月了,而这篇文章原本是打算写在那本书里面的,但本章讲解的内容,毕竟属于CSS未来的范畴,而这一切都还不能够确定下来,所以这一章 ...

  3. 通过三次优化,我将gif加载优化了16.9%

    WeTest 导读 现在app越来越炫,动不动就搞点动画,复杂的动画用原生实现起来挺复杂,如是就搞起gif播放动画的形式,节省开发成本.   背 景 设计同学准备给一个png序列,开发读取png序列, ...

  4. 算法与数据结构(七) AOV网的拓扑排序

    今天博客的内容依然与图有关,今天博客的主题是关于拓扑排序的.拓扑排序是基于AOV网的,关于AOV网的概念,我想引用下方这句话来介绍: AOV网:在现代化管理中,人们常用有向图来描述和分析一项工程的计划 ...

  5. 记录我这一年的技术之路(nodejs纯干货)

    2015年12月28日23:19:54 更新koa应用.学习型网站和开发者工具等 coding伊始 开始认认真真的学习技术还是2015.10.21日开始的,记得很清楚,那天,是我在龙湖正式学习的第一天 ...

  6. Django

    一.Django 简介 Django 是一个由 Python 写成的开放源代码的 Web 应用框架.它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的,即是 CMS(内容管理系统) ...

  7. 《LoadRunner12七天速成宝典》来了

    看到自己的新书又要发行了,算算从09年第一本书开始,不知不觉已经是第四本书了(帮朋友合写的书不算),每次写完之后都会说太累了,不想再写了,但是却又次次反悔,吞下食言的苦果.如果非要说第四本书的感受,那 ...

  8. Hibernate中事务的隔离级别设置

    Hibernate中事务的隔离级别,如下方法分别为1/2/4/8. 在Hibernate配置文件中设置,设置代码如下

  9. iOS 后台处理

    iOS 后台处理的常见用途 1.进入后台时候删除资源:应用处于挂起状态的时候所占用的资源越少,该应用被iOS终止的风险就越低.通过从内存中清理那些易于重新创建的资源,可以增加应用驻留内存的机会,因此可 ...

  10. BPM配置故事之案例1-配置简单流程

    某天,Boss找到了信息部工程师小明. Boss:咱们新上了H3 BPM,你研究研究把现在的采购申请流程加上去吧,这是采购申请单. 小明:好嘞 采购申请单 小明回去后拿着表单想了想,开始着手配置. 他 ...