浅谈 Fragment 生命周期
来源:互联网 发布:电影院里啪啪 知乎 编辑:程序博客网 时间:2024/06/06 15:39
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 生命周期。
- 第一点很重要,最开始的两张图展示的 Fragment 与 Activity 的生命周期关系没毛病。
onAttach()
和onCreate()
只在 Fragment 与 Activity 第一次关联时调用。onDestroy()
和onDetach()
只在 Fragment 的宿主 Activity 销毁时才会被调用。- 根据前 3 点,将 Fragment 通过
addToBackStack()
只涉及onCreateView()
和onDestroyView()
这之间的生命周期。add()
和replace()
不会对 Fragment 的生命周期产生影响,但add()
方法会造成 Fragment 叠加显示。 - Fragment 与 ViewPager 结合使用时的生命周期与第 4 点相似。
- 通过
hide()
、show()
来隐藏、显示Fragment,此时 Fragment 只改变了可见性,并不涉及生命周期的改变 - 第 7 点与Fragment 和 Activity 的生命周期有关,即:不要在 Fragment 的 onCreate() 方法中操作宿主Activity 的 UI。因为你无法保证此时 宿主Activity 的 UI 已经完全初始化。PS:某些情况下是可以确保 宿主Activity 已经初始化完成的。
- 浅谈 Fragment 生命周期
- 浅谈 Fragment 生命周期
- 浅谈Android中的 Fragment、生命周期回调方法 以及使用
- fragment 生命周期
- Fragment生命周期
- Fragment 生命周期
- Fragment生命周期
- Fragment生命周期
- Fragment生命周期
- Fragment生命周期
- fragment 生命周期
- Fragment生命周期
- Fragment生命周期
- Fragment生命周期
- fragment 生命周期
- Fragment生命周期
- Fragment 生命周期
- Fragment生命周期
- SSH免密码登录git
- JSP九大内置对象的作用和用法总结
- Winform应用程序实现通用遮罩层二
- swift闭包的值捕获
- 数据库中的乐观锁和悲观锁
- 浅谈 Fragment 生命周期
- Java实现简单的数据结构(四)
- Python+selenium:获取一组元素属性值
- 为什么在sql查询中需要使用xxx is null而不能使用xxx=null 详解
- 第二次修改状态机源码
- UIFramework之功能分析
- MAC下通过XAMPP和PHPStorm配置PHP开发环境
- PHP简答和程序笔试题目
- hadoop datanode 启动出错