yunshuipiao/Potato

Android Fragment

yunshuipiao opened this issue · 0 comments

Android Fragment

这篇文章讲解 Fragment 的基本概念使用。

基础概念

因为support库是不断更新的,因此建议使用support库中的android.support.v4.app.Fragment,而不要用系统自带的android.app.Fragment。而如果要使用support库的Fragment,Activity必须要继承FragmentActivity(AppCompatActivity是FragmentActivity的子类)

根据官方的定义:

  • framgent 依赖于 Activity,不能独立存在
  • 一个 Activity 中可以有多个 Fragment
  • 一个 Fragment 可以被多个 Activity 重用。
  • Fragment 有自己的生命周期,并能接收输入事件
  • 可以在 Activity 运行时动态的添加和删除 Fragment。

其优势在于:

  • 模块化:逻辑放在 Fragment 中,Activity 管理和同步 Fragment 之间的信息

  • 可重用:多个 Activity 可以重用一个 Fragment 。

  • 可适配:根据硬件的屏幕尺寸,屏幕等可以实现不同的布局。

Fragment 的核心类

  • Fragment:基类,任何创建 Fragment 都需要继承该类
  • FragmentManager:管理和维护 Fragment, 也是抽象类,具体的实现类是 FragmentManagerImpl。
  • FragmentTransaction:对 Fragment 的添加,删除等操作都需要通过事务方式进行,也是抽象类,其实现类是 BackStackRecord。

如果在创建 Fragment时要传入参数,必须通过 setArguments() 方式添加,而不建议通过 Fragment 添加带参数的构造函数。因为 通过前者方式添加,在由于内存紧张导致 Fragment 被系统杀死并恢复时可以保留这些数据。在Fragment的 onAttach() 中通过 getArguments() 获得传进来的参数,并在之后使用这些参数。

onSaveInstanceState()是当activity可能被系统回收的情况下,而且是在onStop()之前。注意是有可能,如果是已经确定会被销毁,比如用户按下了返回键,或者调用了finish()方法销毁activity,则onSaveInstanceState不会被调用。或者也可以说,此方法只有在activity被异常终止的情况下会被调用

onRestoreInstanceState(Bundle savedInstanceState)只有在activity确实是被系统回收,重新创建activity情况下才会被调用,并且是在onStart()之后,onResume()之前的。

懒加载

懒加载主要用于ViewPager且每页是Fragment的情况,场景为微信主界面,底部有4个tab,当滑到另一个tab时,先显示”正在加载”,过一会才会显示正常界面。

默认情况,ViewPager会缓存当前页和左右相邻的界面。实现懒加载的主要原因是:用户没进入的界面需要有一系列的网络、数据库等耗资源、耗时的操作,预先做这些数据加载是不必要的。

这里懒加载的实现思路是:用户不可见的界面,只初始化UI,但是不会做任何数据加载。等滑到该页,才会异步做数据加载并更新UI。

懒加载主要依赖Fragment的setUserVisibleHint(boolean isVisible)方法,当Fragment变为可见时,会调用setUserVisibleHint(true);当Fragment变为不可见时,会调用setUserVisibleHint(false),且该方法调用时机:

  • onAttach()之前,调用setUserVisibleHint(false)。
  • onCreateView()之前,如果该界面为当前页,则调用setUserVisibleHint(true),否则调用setUserVisibleHint(false)。
  • 界面变为可见时,调用setUserVisibleHint(true)
  • 界面变为不可见时,调用setUserVisibleHint(false)

commitAllowingStateLoss

使用Fragment的时候偶尔会有这么一个报错,Can not perform this action after onSaveInstanceState,意思为无法再onSaveInstanceState之后执行该操作,这个操作就是指commit()。

为什么我们会有这种报错呢?

因为我们在使用add(),remove(),replace()等方法将Fragment的变化添加进去,然后在通过commit去提交这些变化(另外,在commit之前可以去调用addToBackState()方法,将这些变化加入到activity管理的back stack中去,这样用户调用返回键就可以回退这些变化了),提交完成之后这些变化就会应用到我们的Fragment中去。但是,这个commit()方法,你只能在avtivity存储他的状态之前调用,也就是onSaveInstanceState()。

activity有一个保存状态的方法和恢复状态的方法。

在onSaveInstanceState()方法之后去调用commit(),就会抛出我们遇到的这个异常,这是因为在onSaveInstanceState()之后调用commit()方法,这些变化就不会被activity存储,即这些状态会被丢失,但我们可以去用commitAllowingStateLoss()这个方法去代替commit()来解决这个问题。