Android Fragment生命周期

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

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

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

fragment_lifecycle

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

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

fragment_and_activity_lifecycle

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

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

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

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

LifeCircleFragment.java

1/** 2 * 测试 Fragment 生命周期,setUserVisibleHint 初始进来时只有默认 Tab 3 */ 4 5public class LifeCircleFragment extends BaseFragment { 6 7 private final String TAG = LifeCircleFragment.class.getSimpleName(); 8 //截取 Fragment.toString() 方法中的标识数字 9 private final String ID = this.toString().substring(this.toString().indexOf("{") + 1, this.toString().length() - 1); 10 private TextView mTvContent; 11 12 //默认 Title 值 13 private String mTitle = "Tab"; 14 15 public static LifeCircleFragment newInstance(String title) { 16 Bundle args = new Bundle(); 17 18 LifeCircleFragment fragment = new LifeCircleFragment(); 19 args.putString(Constant.PARAM_TITLE, title); 20 fragment.setArguments(args); 21 return fragment; 22 } 23 24 /** 25 * 当 Fragment 调用 hide() 、 show() 时回调 26 * @param hidden 27 */ 28 @Override 29 public void onHiddenChanged(boolean hidden) { 30 Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onHiddenChanged.hidden = " + hidden); 31 super.onHiddenChanged(hidden); 32 } 33 34 /** 35 * 当 Fragment 与 ViewPager 结合使用时,切换 Pager 时回调 36 * @param isVisibleToUser 37 */ 38 @Override 39 public void setUserVisibleHint(boolean isVisibleToUser) { 40 Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is setUserVisibleHint.isVisibleToUser = " + isVisibleToUser); 41 super.setUserVisibleHint(isVisibleToUser); 42 } 43 44 /** 45 * Fragment 关联到 Activity 时回调 46 * 此时 Activity 已经与 Fragment 关联,通过 Context 向下转型,就可以与 Activity 通信 47 * 当然也可以使用 getActivity(),前提是这个 fragment 已经和宿主的 activity 关联,并且没有脱离 48 * onAttach 只调用一次。 49 * 50 * @param context 51 */ 52 @Override 53 public void onAttach(Context context) { 54 //由于 onCreate 是在 onAttach 后执行,故此时 mTitle 为空 55 Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onAttach."); 56 super.onAttach(context); 57 } 58 59 /** 60 * 系统创建 Fragment 的时候回调,介于 onAttach() 和 onCreateView() 之间 61 * 一般用于初始化一些数据 62 * 值得注意的是,此时 Activity 还在创建中,因此不能在执行一些跟 Activity UI 相关的操作 63 * 否则,会出现一些难以预料的问题,比如:NullPointException 64 * 如果要对 Activity 上的 UI 进行操作,建议在 onActivityCreated() 中操作 65 * 66 * @param savedInstanceState 67 */ 68 @Override 69 public void onCreate(@Nullable Bundle savedInstanceState) { 70 Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onCreate."); 71 super.onCreate(savedInstanceState); 72 setHasOptionsMenu(true); 73 if (getArguments() != null) { 74 mTitle = getArguments().getString(Constant.PARAM_TITLE); 75 } 76 //测试 onCreate() 是 Activity 的 UI 是否初始化完成 77 //if (getContext() instanceof LifeCircleActivity) { 78 //((LifeCircleActivity) getContext()).setActivityCreated("Fragment 进行 onCreate() 时 Activity UI 尚未初始化完成。" 79 // + "\n你看不到我,因为我已经变成异常抛出了。"); 80 //} 81 } 82 83 /** 84 * 创建 Fragment 需要显示的 View,默认返回 null。 85 * 当返回的 View 不为 null 时,View 被销毁时会调用 onDestroyView() 86 * 此处应该只进行布局的初始化,而不应该执行耗时操作,如网络请求、数据库读取 87 * 88 * @param inflater 89 * @param container 90 * @param savedInstanceState 91 * @return 92 */ 93 @Nullable 94 @Override 95 public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 96 Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onCreateView."); 97 return inflater.inflate(R.layout.fragment_life_circle, container, false); 98 } 99 100 /** 101 * 该方法在 onCreateView() 之后会被立即执行 102 * 此时可以对 View 对象进行赋值,当然在 onCreateView() 中也可以执行 103 * 104 * @param view 105 * @param savedInstanceState 106 */ 107 @Override 108 public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 109 Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onViewCreated."); 110 super.onViewCreated(view, savedInstanceState); 111 mTvContent = (TextView) view.findViewById(R.id.tv_content); 112 mTvContent.setText(mTitle); 113 } 114 115 /** 116 * 当 Activity 执行完 onCreate() 方法后调用 117 * 此时可以执行与 Activity 相关的 UI 操作 118 * 119 * @param savedInstanceState 120 */ 121 @Override 122 public void onActivityCreated(@Nullable Bundle savedInstanceState) { 123 Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onActivityCreated."); 124 super.onActivityCreated(savedInstanceState); 125 //测试 onCreate() 是 Activity 的 UI 是否初始化完成 126 if (getContext() instanceof SimpleLifeCircleActivity) { 127 ((SimpleLifeCircleActivity) getContext()).setActivityCreated("Fragment 进行 onActivityCreated() 时 Activity UI 已初始化完成。" 128 + "\n你能看到我。"); 129 } 130 } 131 132 @Override 133 public void onViewStateRestored(@Nullable Bundle savedInstanceState) { 134 Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onViewStateRestored."); 135 super.onViewStateRestored(savedInstanceState); 136 } 137 138 /*-----------跟 Activity 中对应方法类似-------------*/ 139 @Override 140 public void onStart() { 141 Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onStart."); 142 super.onStart(); 143 } 144 145 @Override 146 public void onResume() { 147 Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onResume."); 148 super.onResume(); 149 } 150 151 @Override 152 public void onPause() { 153 Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onPause."); 154 super.onPause(); 155 } 156 157 @Override 158 public void onStop() { 159 Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onStop."); 160 super.onStop(); 161 } 162 /*-----------跟 Activity 中对应方法类似-------------*/ 163 164 /** 165 * 表示销毁 Fragment 相关联的 UI 布局,清除所有跟视图相关的资源。 166 * 不一定在 Activity 的 onDestroy() 方法中调用 167 * 如:Fragment 与 ViewPager 结合使用时 168 * 169 * @see com.littlejie.fragment.lifecircle.LifeCircleWithViewPagerActivity 170 */ 171 @Override 172 public void onDestroyView() { 173 Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onDestroyView."); 174 super.onDestroyView(); 175 } 176 177 /** 178 * 销毁 Fragment 对象的时候调用,一般是调用 Activity 的 onDestroy() 的时候执行 179 */ 180 @Override 181 public void onDestroy() { 182 //当调用 Activity 的 onDestroy() 时调用 183 Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onDestroy."); 184 super.onDestroy(); 185 } 186 187 /** 188 * 解除 Fragment 与 Activity 的关联 189 */ 190 @Override 191 public void onDetach() { 192 Log.i(TAG, "Fragment id = " + ID + "," + mTitle + " is onDetach."); 193 super.onDetach(); 194 } 195 196}

由于日志过多,这里不再展示,有兴趣的可自行下载 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 已经初始化完成的。

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

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )

这是一份用心整理的Android面试总结,涨姿势!

AndroidJetpack组件的作用是什么?Navigation:一个用于管理Fragment切换的工具类,可视化、可绑定控件、支持动画等是其优点。DataBinding:不用说,都知道,加速MVVM的创建。Lifecycle:他是我们能够处理Activity和Fragment的生命周期的重要原因,在AndroidX的Fragment和Activ