Fragment 用法总结(二)

Fragment 用法总结(二)

上一篇文章里主要讲到Fragment如何创建,如何与Activity交互,基本的API用法等。有兴趣可以先了解下Fragment 用法总结(一)。

Fragment的生命周期大家都熟悉,本篇文章主要从Activity管理Fragment的角度来了解Fragment的生命周期变化,并与Activity的生命周期协调一致。

Fragment的生命周期

Fragment 用法总结(二)_第1张图片

通常,我们的Fragment至少应实现以下生命周期方法:

  • onCreate()
    系统会在创建Fragment时调用此方法。我们应该在这个方法里初始化那些在Fragment暂停或停止后恢复时必需保留的Fragment组件。
  • onCreateView()
    系统会在Fragment首次绘制其用户界面时调用此方法。 要想为Fragment绘制 UI,从此方法中返回的 View 必须是Fragment布局的根视图。如果Fragment未提供 UI,可以返回 null。
  • onPause()
    系统将此方法作为用户离开Fragment的第一个信号(但并不总是意味着此Fragment会被销毁)进行调用。 通常应该在此方法内保存一些将来需要恢复的数据(因为用户可能不会返回)。

其它生命周期方法的作用在下面会讲到。

处理Fragment生命周期

Fragment 用法总结(二)_第2张图片

管理Fragment生命周期与管理 Activity 生命周期很相似。和 Activity 一样,Fragment也以三种状态存在:

  • 恢复
    Fragment在运行中的 Activity 中可见。

  • 暂停
    另一个 Activity 位于前台并具有焦点,但此Fragment所在的 Activity 仍然可见(前台 Activity 部分透明,或未覆盖整个屏幕)。

  • 停止
    Fragment不可见。宿主 Activity 已停止,或Fragment已从 Activity 中删除,但已添加到返回栈。 停止Fragment仍然处于活动状态(系统会保留所有状态和成员信息)。 不过,它对用户不再可见,如果 Activity 被终止,它也会被终止。
    同样与 Activity 一样,假使 Activity 的进程被终止,而需要在重建 Activity 时恢复Fragment状态,可以使用 Bundle 保留Fragment的状态。可以在Fragment的 onSaveInstanceState() 回调期间保存状态,并可在 onCreate()、onCreateView() 或 onActivityCreated() 期间恢复状态。

Activity 生命周期与Fragment生命周期之间的最显著差异在于它们在其各自返回栈中的存储方式。 默认情况下,Activity 停止时会被放入由系统管理的 Activity 返回栈(以便用户通过“返回” 按钮回退到Activity)。不过,Fragment只有在Fragment的事务执行期间通过调用 addToBackStack() 显式请求保存实例时,系统才会将Fragment放入由宿主 Activity 管理的返回栈。

在其他方面,管理Fragment生命周期与管理 Activity 生命周期非常相似。 因此,管理 Activity 生命周期的做法同样适用于Fragment。 但还需要了解 Activity 的生命周期对Fragment生命周期的影响。

注意:如需 Fragment 内的某个 Context 对象,可以调用 getActivity()。但要注意,请仅在Fragment附加到 Activity 时调用 getActivity()。如果Fragment尚未附加,或在其生命周期结束期间分离,则 getActivity() 将返回 null,所以getActivity()和getContext()(API level 23 新增方法)要在Fragment回调函数onAttach之后才能调用。

与 Activity 生命周期协调一致

Fragment所在的 Activity 的生命周期会影响Fragment的生命周期,其表现为,Activity 的每次生命周期回调都会引发每个Fragment的类似回调。 例如,当 Activity 收到 onPause() 时,Activity 中的每个Fragment也会收到 onPause()。

不过,Fragment还有几个额外的生命周期回调,用于处理与 Activity 的唯一交互,以执行构建和销毁Fragment UI 等操作。这些额外的回调方法是:

  • onAttach()
    在Fragment已与 Activity 关联时调用(Activity 传递到此方法内)。
  • onCreateView()
    调用它可创建与Fragment关联的视图层次结构。
  • onActivityCreated()
    在 Activity 的 onCreate() 方法已返回时调用。
  • onDestroyView()
    在删除与Fragment关联的视图层次结构时调用。
  • onDetach()
    在取消Fragment与 Activity 的关联时调用。

宿主 Activity 影响Fragment的生命周期流。Activity 的每个连续状态如何决定Fragment可以收到的回调方法。 例如,当 Activity 收到其 onCreate() 回调时,Activity 中的Fragment只会收到 onActivityCreated() 回调。

一旦 Activity 达到恢复状态,就可以意向 Activity 添加Fragment和删除其中的Fragment。 因此,只有当 Activity 处于恢复状态时,Fragment的生命周期才能独立变化。

不过,当 Activity 离开恢复状态时,Fragment会在 Activity 的推动下再次经历其生命周期。

Fragment的生命周期如何变化

我们结合Activity对fragment的操作方法,了解一下不同的操作方法对Fragment的生命周期方法的影响。

下面是动图操作的步骤:
一、fragmentTransaction.add(R.id.content_main, fragmentA).commit();

FragmentA: onAttach;
FragmentA: onCreate;
FragmentA: onCreateView;
FragmentA: onActivityCreated;
FragmentA: onStart;
FragmentA: onResume;

为Activity添加第一个Fragment的时候不要把事物添加到返回栈,如果添加了,则会在“返回”按钮按下后回退到Activity的空白页面,这应该是大家不想看到的。
二、fragmentTransaction.replace(R.id.content_main, fragmentB).addToBackStack(null).commit();

FragmentA: onPause;
FragmentA: onStop;
FragmentA: onDestroyView;
FragmentB: onAttach;
FragmentB: onCreate;
FragmentB: onCreateView;
FragmentB: onActivityCreated;
FragmentB: onStart;
FragmentB: onResume;

FragmentTransaction的replace方法相当于remove方法和add方法的结合,上面的程序输出也证明了这一点
三、fragmentTransaction.hide(fragmentB).add(R.id.content_main, fragmentC).addToBackStack(null).commit();

FragmentC: onAttach;
FragmentC: onCreate;
FragmentC: onCreateView;
FragmentC: onActivityCreated;
FragmentC: onStart;
FragmentC: onResume;

FragmentTransaction的hide方法不触发Fragment的生命周期方法,所以隐藏FragmentB没有触发接下来的生命周期,上面的输出表明这个事物提交后只触发了添加fragmentC的生命周期方法。
四、fragmentTransaction.detach(fragmentC).addToBackStack(null).commit();

FragmentC: onPause;
FragmentC: onStop;
FragmentC: onDestroyView;

将fragmentC detach
五、按下返回键 popBackStack

FragmentC: onCreateView;
FragmentC: onActivityCreated;
FragmentC: onStart;
FragmentC: onResume;

返回操作,恢复到detach FragmentC的状态,FragmentC从detach状态变为attach状态
六、按下返回键 popBackStack FragmentC被移除

FragmentC: onPause;
FragmentC: onStop;
FragmentC: onDestroyView;
FragmentC: onDestroy;
FragmentC: onDetach;

返回操作,恢复到加载FragmentC前的状态,上一个提交的事物为hide->FragmentB add ->FragmentC 则恢复操作相反 “remove->FragmentC” “show->FragmentB”,
上面讲到hide方法不触发Fragment生命周期,同理show方法也不触发Fragment生命周期。
由于FragmentC已经退出”历史舞台”取消与Activity关联,所以执行onDetach方法。
七、按下返回键 popBackStack FragmentB

FragmentB: onPause;
FragmentB: onStop;
FragmentB: onDestroyView;
FragmentB: onDestroy;
FragmentB: onDetach;
FragmentA: onCreateView;
FragmentA: onActivityCreated;
FragmentA: onStart;
FragmentA: onResume;

返回操作,恢复到加载FragmentB前的状态,则replace的逆操作“remove FragmentB” “add FragmentA”
八、按下返回键 popBackStack FragmentA

FragmentA: onPause;
FragmentA: onStop;
FragmentA: onDestroyView;
FragmentA: onDestroy;
FragmentA: onDetach;

返回操作,恢复到加载FragmentA前的状态,没有加入回退栈,Activity直接退出。

眼尖的同学肯定发现了,上面动态图片中FragmentA的EditView设置了新内容,但是在回退回来的时候,又恢复到原来的内容。这是因为:如果不给一个View设置一个id,那么在Activity或者Fragment调用onSaveInstanceState(Bundle outState)方法时,就没办法保存它的状态,这会导致在恢复界面的时候丢失上次的状态。

切换Fragment的方法


  • hide(A).add(B).addToBackStack(null).commit();
    这种方法FragmentA在hide和恢复的时候不会触发生命周期回调方法。
  • replace(id,B).addToBackStack(null).commit();
    这种方法FragmentA在replace和恢复的时候会走一遍生命周期函数。replace和remove + add效果一样。
  • detach(A).add(B).addToBackStack(null).commit();
    这里detach会销毁FragmentA的视图,添加到回退栈后“返回”可以恢复视图,这里也要触发FragmentA生命周期回调方法。

注意:当你移除或替换 Fragment 并向返回堆栈添加事务时,已移除的 Fragment 会停止(而不是销毁)。如果用户向后导航,还原该 Fragment,它会重新启动。如果你没有向返回堆栈添加事务,那么该 Fragment 在移除或替换时就会被销毁。

Fragment的视图状态

  • Fragment返回时中保留View状态
    首先要调用addToBackStack()把切换事物加到回退栈里,保证Fragment能成功返回,其次不要每次都new一个新的Fragment对象,保存Fragment实例。这里要注意屏幕横竖切换的时候Fragment会重叠。
  • Fragment返回时中不保留View状态
    切换Fragment的事物里每次new一个新的Fragment或者不给视图添加id就可以(好像没什么意义)。

如果是非应用行为导致Fragment异常退出和恢复,在onSaveInstanceState()里保存状态。

上面动图的示例代码

本篇文章主要从Activity管理Fragment的角度来了解Fragment的生命周期变化,并与Activity的生命周期协调一致。下一篇Fragment 用法总结(三)主要介绍:没有视图的Fragment的用处、使用Fragment创建对话框、如何与ActionBar和MenuItem集成等高级用法。

你可能感兴趣的:(Fragment 用法总结(二))