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

微博:厉圣杰

源码:AndroidDemo/Fragment

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

之前写过一篇关于 Fragment 生命周期的文章,针对 Fragment 各种情况下的生命周期进行了讨论,这段时间对 Fragment 的使用次数逐渐增加,对 Fragment 也有一定的了解,写此文以做总结。本文中使用 support library v4 包中的 Fragment。

本文大致会从以下几个方面对 Fragment 进行总结,如有不当之处,欢迎指出~

Fragment 简介

Fragment 是在 Android 3.0 中引入,主要用于在大屏设备(如平板电脑)上支持更多动态和灵活的 UI 设计。 因为平板的屏幕比手机屏幕大得多,所以有更多的空间放更多的 UI 控件,也会产生更多的交互。Fragment 可以将 Activity 中的 UI 划分到自身,以实现在多个 Activity 中重用。

下图来自 Android 官方文档,很好的说明了 Fragment 的设计理念:

当在平板电脑上运行时,App 可以在 Activity A 中嵌入 2 个 Fragment。当用户在 Fragment A 中选中某个 Item 时就可以直接在 Fragment B 中展示内容。而在手机等小屏幕设备上,由于没有足够的空间,Activity A 只能展示 Fragment A,并且只能通过启动 Activity B 才能展示选中 Item 的内容。

Fragment 有自己的布局,有自己的生命周期,有自己的响应事件。但 Fragment 又依赖于 Activity 的存在,你可以把多个 Fragment 嵌入到一个 Activity 中或者多个 Activity 重用一个 Fragment。Activity 的生命周期直接影响 Fragment 的生命周期。在 Activity 运行过程中,可以添加、移除或者替换Fragment。

Fragment 使用比较多的直接子类有:

  1. DialogFragment:一种特殊的 Fragment ,可以创建类似 Dialog 的对话框。
  2. 因为是 Fragment ,所以可以管理其生命周期。官方推荐使用。
  3. ListFragment:类似于 ListActivity
  4. PreferenceFragment:类似于 PreferenceActivity

关于 Fragment 子类的使用方式本文不在赘述,有兴趣的可以自行上网搜索~

Fragment 的创建

Fragment 可以通过 XML 静态添加,也可以通过代码动态添加,而动态添加又可以分为通过 new 一个Fragment 和通过 newInstance() 生成一个 Fragment 实例。

静态添加Fragment

首先,我们创建一个布局文件 fragment_test.xml:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="vertical">
  6. <TextView
  7. android:id="@+id/tv_content"
  8. android:layout_width="match_parent"
  9. android:layout_height="match_parent"
  10. android:gravity="center"
  11. android:text="This is a Fragment"
  12. android:textSize="20sp" />
  13. </LinearLayout>

然后创建 TestFragment,该类继承作者自己封装的 BaseFragment ,与系统自带的 Fragment 有些许差异,但不影响理解

  1. public class TestFragment extends BaseFragment {
  2. @BindView(R.id.tv_content)
  3. TextView mTvContent;
  4. private String mTitle;
  5. private int mBgColor;
  6. public static TestFragment newInstance(String title, int bgColor) {
  7. Bundle args = new Bundle();
  8. TestFragment fragment = new TestFragment();
  9. args.putString(Constant.EXTRA_TITLE, title);
  10. args.putInt(Constant.EXTRA_COLOR, bgColor);
  11. fragment.setArguments(args);
  12. return fragment;
  13. }
  14. @Override
  15. protected int getPageLayoutID() {
  16. return R.layout.fragment_test;
  17. }
  18. @Override
  19. protected void initData() {
  20. if (getArguments() == null) {
  21. return;
  22. }
  23. mTitle = getArguments().getString(Constant.EXTRA_TITLE);
  24. mBgColor = getArguments().getInt(Constant.EXTRA_COLOR);
  25. }
  26. @Override
  27. protected void initView(View view, Bundle savedInstanceState) {
  28. if (!TextUtils.isEmpty(mTitle)) {
  29. mTvContent.setText(mTitle);
  30. }
  31. mTvContent.setBackgroundColor(mBgColor);
  32. }
  33. @Override
  34. protected void initViewListener() {}
  35. @Override
  36. protected void process(Bundle savedInstanceState) {}
  37. }

接下去,在 Activity 的布局文件中添加 TestFragment 即可,使用方法与普通控件相似。

activity_static_create.xml:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:tools="http://schemas.android.com/tools"
  4. android:id="@+id/activity_static_create"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. tools:context="com.littlejie.demo.modules.base.fragment.create.StaticCreateActivity">
  8. <!-- name 属性用于指定使用哪个 Fragment -->
  9. <fragment
  10. android:name="com.littlejie.demo.modules.base.fragment.create.TestFragment"
  11. android:layout_width="match_parent"
  12. android:layout_height="match_parent" />
  13. </LinearLayout>

Activity 布局相对简单,这里就不再展示代码。运行效果如下:

动态添加 Fragment

现在我们已经学会了如何在 XML 中静态添加 Fragment,但这只是最基础的使用。Fragment 的强大之处在于其可以动态的添加到 Activity 当中。

这里我们依旧使用上一节中 TestFragment 的代码,这也是 Fragment 复用性的体现。

主界面由两个 Button 和一个 FrameLayout 组成。

activity_dynamic_create.xml:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:tools="http://schemas.android.com/tools"
  4. android:id="@+id/activity_dynamic_create"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. android:orientation="vertical"
  8. tools:context="com.littlejie.demo.modules.base.fragment.create.DynamicCreateActivity">
  9. <Button
  10. android:id="@+id/btn_show_fragment1"
  11. android:layout_width="match_parent"
  12. android:layout_height="wrap_content"
  13. android:text="显示Fragment1" />
  14. <Button
  15. android:id="@+id/btn_show_fragment2"
  16. android:layout_width="match_parent"
  17. android:layout_height="wrap_content"
  18. android:text="显示Fragment2" />
  19. <FrameLayout
  20. android:id="@+id/fragment_container"
  21. android:layout_width="match_parent"
  22. android:layout_height="match_parent" />
  23. </LinearLayout>

DynamicCreateActivity 继承自作者封装的 BaseActivity,代码如下:

  1. public class DynamicCreateActivity extends BaseActivity {
  2. @Override
  3. protected int getPageLayoutID() {
  4. return R.layout.activity_dynamic_create;
  5. }
  6. @Override
  7. protected void initData() {}
  8. @Override
  9. protected void initView() {}
  10. @Override
  11. protected void initViewListener() {}
  12. @Override
  13. protected void process() {}
  14. @OnClick(R.id.btn_show_fragment1)
  15. public void showFragment1() {
  16. showFragment(TestFragment.newInstance("This is Fragment1", Color.YELLOW));
  17. }
  18. @OnClick(R.id.btn_show_fragment2)
  19. public void showFragment2() {
  20. showFragment(TestFragment.newInstance("This is Fragment2", Color.CYAN));
  21. }
  22. private void showFragment(Fragment fragment) {
  23. FragmentManager fragmentManager = getSupportFragmentManager();
  24. FragmentTransaction transaction = fragmentManager.beginTransaction();
  25. transaction.replace(R.id.fragment_container, fragment);
  26. transaction.commit();
  27. }
  28. }

程序运行效果如图:

![2017-01-23 14_49_51-w300](http://odsdowehg.bkt.clouddn.com/2017-01-23 14_49_51.gif)

动态添加 Fragment 的主要逻辑集中在 showFragment() 中,该过程可以分解为以下几步:

  1. 1. 获取 FragmentManager ,在 V4 包中通过 `getSupportFragmentManager()`,在系统中原生的 Fragment 是通过 `getFragmentManager()` 获得的。
  2. 2. 调用 `beginTransaction()` 开启事务
  3. 3. FrameLatout 添加 Fragment,一般使用 add() 或者replace() 方法实现,需要传入容器的 id Fragment 的实例
  4. 4. 调用 `commit()` 方法提交事务

通过上述例子,你是不是对 Fragment 的使用有了初步的了解呢?

补充:new Fragment 与 newInstance() 的区别

当系统内存不足时,Fragment 可能会被销毁,当其再次实例化时,系统只会调用 Fragment 的无参构造函数,一些需要外部传入的参数的初始化过程就无法完成。而通过 newInstance() 方式就可以将外部传入的在 Fragment 内部,在 Fragment 调用 onCreate() 时将其取出初始化。

  1. public static Fragment instantiate(Context context, String fname, @Nullable Bundle args) {
  2. try {
  3. Class<?> clazz = sClassMap.get(fname);
  4. if (clazz == null) {
  5. // Class not found in the cache, see if it's real, and try to add it
  6. clazz = context.getClassLoader().loadClass(fname);
  7. sClassMap.put(fname, clazz);
  8. }
  9. Fragment f = (Fragment)clazz.newInstance();
  10. if (args != null) {
  11. args.setClassLoader(f.getClass().getClassLoader());
  12. f.mArguments = args;
  13. }
  14. return f;
  15. } catch (ClassNotFoundException e) {
  16. throw new InstantiationException("Unable to instantiate fragment " + fname
  17. + ": make sure class name exists, is public, and has an"
  18. + " empty constructor that is public", e);
  19. } catch (java.lang.InstantiationException e) {
  20. throw new InstantiationException("Unable to instantiate fragment " + fname
  21. + ": make sure class name exists, is public, and has an"
  22. + " empty constructor that is public", e);
  23. } catch (IllegalAccessException e) {
  24. throw new InstantiationException("Unable to instantiate fragment " + fname
  25. + ": make sure class name exists, is public, and has an"
  26. + " empty constructor that is public", e);
  27. }
  28. }

Fragment 中的重要方法

上一节我们学习了 Fragment 的创建方式,算是对 Fragment 的使用有了初步了解,也使用了 Fragment 中的一些方法,但仅仅这样是不够的。下面,我们来系统的学习下 Fragment 使用中常见的方法。

FragmentManager

FragmentManager 用于管理 Fragment,可以通过 getSupportFragmentManager()getChildFragmentManager() 获取,但两者之间是有差异的。

  1. /**
  2. * 管理 Activity 中的 Fragment,对于 support library v4 包下的 Fragment。
  3. * 类似的有 getFragmentManager() ,不过该方法只支持 Android 3.0 以上。
  4. */
  5. void getSupportFragmentManager()
  6. /**
  7. * 管理 Fragment 内嵌的 Fragment,要与前者区别开,否则会造成很郁闷的问题。如:add()、replace()、getBackStackEntryCount() 操作的结果会与预期不一致。
  8. */
  9. void getChildFragmentManager();

FragmentManager 使用频率比较高的有以下方法:

  1. /**
  2. * 开启事务,用于 Fragment 的处理
  3. */
  4. FragmentTransaction beginTransaction();
  5. /**
  6. * 将 Fragment 从回退栈中弹出,需要与 addToBackStack() 配合使用
  7. * 若回退栈不为空,按返回键时默认弹出回退栈顶端的 Fragment
  8. */
  9. void popBackStack();
  10. /**
  11. * 针对第一个参数,如果 name 为 null,那么只有顶部的状态被弹出;
  12. * 如果 name 不为 null,并且找到了这个 name 所指向的 Fragment 对象;
  13. * 根据 flags 的值,如果是 flag = 0 ,那么将会弹出该状态以上的所有状态;
  14. * 如果 flag = POP_BACK_STACK_INCLUSIVE ,那么将会弹出该状态(包括该状态)以上的所有状态。
  15. */
  16. void popBackStack(String name, int flags);
  17. /**
  18. * 针对第一个参数,如果该 id 找不到,那么什么都不做;
  19. * 否则根据 flags 的值,如果是 flag = 0 ,那么将会弹出该状态以上的所有状态;
  20. * 如果 flag = POP_BACK_STACK_INCLUSIVE ,那么将会弹出该状态(包括该状态)以上的所有状态。
  21. */
  22. void popBackStack(int id, int flags);
  23. /**
  24. * 和 popBackStack(int id, int flags) 类似,不同的是这个事立马弹出,和 executePendingTransactions() 方法之后的效果一样。
  25. * 如果有东西弹出,返回为 true ;否则就是 false 。
  26. */
  27. boolean popBackStackImmediate();
  28. /**
  29. * 获取回退栈中 Fragment 的个数
  30. */
  31. int getBackStackEntryCount();
  32. /**
  33. * 根据序号返回后台堆栈中的BackStackEntry对象,最底的序号为0。
  34. */
  35. FragmentManager.BackStackEntry getBackStackEntryAt(int index);
  36. /**
  37. * 通过 tag 查找 Fragment,这个 tag 可以是 XML 中的,也可以是通过事务动态添加的
  38. */
  39. Fragment findFragmentByTag(String tag);
  40. /**
  41. * 通过 id 查找 Fragment,这个 id 可以是 XML 中的,也可以是通过事务动态添加的
  42. */
  43. Fragment findFragmentById(int id);
  44. /**
  45. * 抽象方法,为 Fragment 的回退栈添加一个监听器,用于监听堆栈的改变情况。
  46. */
  47. public abstract void addOnBackStackChangedListener(OnBackStackChangedListener listener);
  48. /**
  49. * 抽象方法,移除回退栈的监听器
  50. */
  51. public abstract void removeOnBackStackChangedListener(OnBackStackChangedListener listener);

FragmentTransaction


  1. boolean add():将一个 Fragment 实例添加到最顶端
  2. /**
  3. * 将 Fragment 添加到回退栈,
  4. */
  5. addToBackStack():
  6. replace():
  7. show():
  8. hide():
  9. commit():

Fragment

以下方法主要用于判断 Fragment 的状态,如可见性等,后续会详细讲解。

  1. /**
  2. * 获取当前 Fragment 的父 Fragment。
  3. * 如果该 Fragment 是直接添加在 Activity 上,那么返回 null
  4. */
  5. Fragment getParentFragment();
  6. /**
  7. * 如 TestFragment 中,该方法主要为 Fragment 提供一些初始化数据
  8. * 数据以 Bundle 形式封装传递。
  9. */
  10. void setArguments(Bundle args);
  11. /**
  12. * 获取传递给 Fragment 的参数
  13. */
  14. Bundle getArguments();
  15. /**
  16. * 判断 Fragment 是否已经添加到 Activity 上
  17. */
  18. boolean isAdded();
  19. /**
  20. *
  21. */
  22. boolean isHidden();
  23. void onHiddenChanged();
  24. boolean isVisible();
  25. void setVisibleToUser();
  26. boolean getUserVisibleHint();

Fragment 的生命周期

现在,我们对 Fragment 的使用已经有了详尽的认识。但是,有句古话说的好:工欲善其事,必先利其器。要对 Fragment 有透彻的认识,还得掌握它的生命周期。

阎王叫你五更死,你活不到三更

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

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

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

Fragment 的生命周期这样就讲完了?理论上来说,是的。但是,我还有话要讲~

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

![屏幕快照 2017-01-04 下午8.30.54-w400](http://odsdowehg.bkt.clouddn.com/屏幕快照 2017-01-04 下午8.30.54.png)

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

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

项目结构如下

![屏幕快照 2017-01-04 下午8.43.37-w400](http://odsdowehg.bkt.clouddn.com/屏幕快照 2017-01-04 下午8.43.37.png)

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

LifeFragment.java

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

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

Fragment 交互

Fragment 状态(可见性)

Fragment 创建菜单

参考

  1. Fragments

Android Fragment 详解(未完...)的更多相关文章

  1. Android Fragment详解

    一.什么是Fragment Android在3.0中引入了fragments的概念,主要目的是用在大屏幕设备上--例如平板电脑上,支持更加动态和灵活的UI设计.平板电脑的屏幕要比手机的大得多,有更多的 ...

  2. android——fragment详解

    在android开发过程中,如果使用到了导航栏.那么不可避免的就需要使用fragment来处理界面.闲着没事,就详解一下Framgent的使用方法吧. 难得写一次.本人 shoneworn shone ...

  3. Android Fragment 详解(一)

    Android从3.0开始引入fragment,主要是为了支持更动态更灵活的界面设计,比如在平板上的应用.平板机上拥有比手机更大的屏幕空间来组合和交互界面组件们.Fragment使你在做那样的设计时, ...

  4. Android Fragment详解(二):Fragment创建及其生命周期

    Fragments的生命周期 每一个fragments 都有自己的一套生命周期回调方法和处理自己的用户输入事件. 对应生命周期可参考下图: 创建片元(Creating a Fragment) To c ...

  5. Android Fragment详解(一):概述

    Fragment是activity的界面中的一部分或一种行为.你可以把多个Fragment们组合到一个activity中来创建一个多面界面并且你可以在多个activity中重用一个Fragment.你 ...

  6. Android Fragment详解(六):Fragement示例

    把条目添加到动作栏 你的fragment们可以向activity的菜单(按Manu键时出现的东西)添加项,同时也可向动作栏(界面中顶部的那个区域)添加条目,这都需通过实现方法onCreateOptio ...

  7. Android Fragment详解(三): 实现Fragment的界面

    为fragment添加用户界面: Fragment一般作为activity的用户界面的一部分,把它自己的layout嵌入到activity的layout中. 一个 要为fragment提供layout ...

  8. Android Fragment详解(五):Fragment与Activity通讯

    与activity通讯 尽管fragment的实现是独立于activity的,可以被用于多个activity,但是每个activity所包含的是同一个fragment的不同的实例. Fragment可 ...

  9. Android Fragment详解(四):管理Fragment

    要管理fragment们,需使用FragmentManager,要获取它,需在activity中调用方法getFragmentManager(). 你可以用FragmentManager来做以上事情: ...

随机推荐

  1. 13-JS中的面向对象

    创建对象的几种常用方式 1.使用Object或对象字面量创建对象 2.工厂模式创建对象 3.构造函数模式创建对象 4.原型模式创建对象 1.使用Object或对象字面量创建对象 JS中最基本创建对象的 ...

  2. 分享一些 Java 无关基础方面的书籍

    个人认为看书有两个点好处: 1. 能出版出来的书一定是经过反复思考,雕琢和审核的,因此从专业性的角度来说,一本好书的价值超其他资料 2. 对着书上的代码自己敲的时候方便 “看完书之后再次提升自我的最好 ...

  3. ie6 表格td中无内容时不显示边框的解决办法

    1.在单元格中加入一个空格.这样: <td> </td> 2.直接在table里这样写:<table border="0" cellspacing=& ...

  4. SpringBoot入门小案例

    1.创建一个简单的maven project项目 2.下面来看一下项目结构: 3.pom.xml 配置jar包 <parent> <groupId>org.springfram ...

  5. RzPageControl Tab拖拽 移动

  6. django----数据库操作(对model增删改查)

    优化查询 articles_list=models.Article.objects.all().iterator() for i in articles_list: print(i.title) 添加 ...

  7. python+selenium十一:jQuery和js语法、js处理iframe

    selenium 执行jQuery/js语法 driver.execute_script(jQuery/js) 1.jQuery jQuery只支持css语法: jquery = '$(CSS).va ...

  8. unittest中更多的测试用例

    随着软件功能的不断增加,对应的测试用例也会呈指数级增长.一个实现几十个功能的项目,对应的单 元测试用例可能达到上百个.如果把所有的测试用例都写在一个 test.py 文件中,那么这个文件会越来越臃肿, ...

  9. Mac下Eclipse读取不到环境变量

    问题: 用Eclipse时候读取不到 ~/.bash_profile 下定义的环境变量,确切的说,是GUI应用读取不到终端的(如eclipse) 解决: 1,下载启动代理器: curl https:/ ...

  10. SpringMVC的初始

    1:其实一开始对SSH和SSM并不是很熟悉的,对SSH可能熟悉些(Struts,Spring,Hibernate)这三个框架.但是由于框架的更新,和出现了更好的框架,一些老框架就被淘汰了,但是呢,一些 ...