Fragment - 温故知新

288 阅读6分钟

Fragment是什么

Fragment看起来和Activity一样,是一个用户界面。可以结合多个Fragments到一个activity中来构建一个有多方面功能的UI,还可以重用同一个Fragment在多个activities中。Fragment可以当成是activity的一个组件,每个Fragment有单独的生命周期,可以在activity运行时进行添加和移除Fragment。因此,相比较于activity,Fragment更加轻量级,更加灵活。

生命周期方法

fragment_lifecycle.png

onAttach
public void onAttach(@NonNull Context context) {
    mCalled = true;
    final Activity hostActivity = mHost == null ? null : mHost.getActivity();
    if (hostActivity != null) {
        mCalled = false;
        onAttach(hostActivity);
    }
}
public void onAttach(@NonNull Activity activity) {
    mCalled = true;
}

onAttach() 是一个 Fragment 和它的 Context 关联时第一个调用的方法,这里我们可以获得对应的Context或者Activity,可以看到这里拿到的Activity是mHost.getActivity(),后面我们介绍FragmentManager 时介绍这个方法。

onCreate()
public void onCreate(@Nullable Bundle savedInstanceState) {
    mCalled = true;
    restoreChildFragmentState(savedInstanceState);
    if (!mChildFragmentManager.isStateAtLeast(Fragment.CREATED)) {
        mChildFragmentManager.dispatchCreate();
    }
}
void restoreChildFragmentState(@Nullable Bundle savedInstanceState) {
    if (savedInstanceState != null) {
        Parcelable p = savedInstanceState.getParcelable(
                FragmentActivity.FRAGMENTS_TAG);
        if (p != null) {
            mChildFragmentManager.restoreSaveState(p);
            mChildFragmentManager.dispatchCreate();
        }
    }
}

onCreate() 在 onAttach() 后调用,用于做一些初始化操作。需要注意的是,Fragment 的 onCreate() 调用时关联的 Activity 可能还没创建好,所以这里不要有依赖外部 Activity 布局的操作。如果有依赖 Activity 的操作,可以放在onActivityCreate()中。

从上面的代码还可以看到,如果是从旧状态中恢复,会执行子 Fragment 状态的恢复,此外还在onCreate() 中调用了子 Fragment 管理者的创建。

onCreateView()
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
        @Nullable Bundle savedInstanceState) {
    if (mContentLayoutId != 0) {
        return inflater.inflate(mContentLayoutId, container, false);
    }
    return null;
}

在 onCreate() 后就会执行 onCreatView() ,这个方法返回一个 View,默认返回为 null。当我们需要在 Fragment 中显示布局时,需要重写这个方法,返回要显示的布局。 后面布局销毁时就会调用 onDestroyView() 。

public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
}

onViewCreate() 不是生命周期中的方法,但是却很有用。它会在 onCreateView() 返回后立即执行,参数中的 view 就是之前创建的 View,因此我们可以在onViewCreate() 中进行布局的初始化.

onActivityCreated
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    mCalled = true;
}

onActivityCreated() 会在 Fragment 关联的 Activity 创建好、Fragment 的布局结构初始化完成后调用。可以在这个方法里做些和布局、状态恢复有关的操作.

public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
    mCalled = true;
}

onViewStateRestored() 方法会在 onActivityCreated() 结束后调用,用于一个 Fragment 在从旧的状态恢复时,获取状态 saveInstanceState 恢复状态,比如恢复一个 check box 的状态。经过这四步,Fragment 创建完成,同步于 Activity 的创建过程.

onStart()
@MainThread
@CallSuper
public void onStart() {
    mCalled = true;
}

onStart() 当 Fragment 可见时调用,同步于 Activity 的 onStart() 。

onResume()
@MainThread
@CallSuper
public void onResume() {
    mCalled = true;
}

onResume()当Fragment 可见并且可以与用户交互时调用。它和Activity的onResume()同步。

onPause()
@MainThread
@CallSuper
public void onPause() {
    mCalled = true;
}

onPause() 当 Fragment 不再可见时调用。也和 Activity 的 onPause() 同步。

onStop()
@MainThread
@CallSuper
public void onStop() {
    mCalled = true;
}

onStop() 当 Fragment 不再启动时调用,和 Activity.onStop() 一致。

onDestroyView()
@MainThread
@CallSuper
public void onDestroyView() {
    mCalled = true;
}

当onCreateView()返回的布局(不论是不是null)从Fragment中解除绑定时调用 onDestroyView().下次 Fragment 展示时,会重新创建布局。

onDestroy()
@MainThread
@CallSuper
public void onDestroy() {
    mCalled = true;
}

当 Fragment 不再使用时会调用 onDestroy() ,它是一个 Fragment 生命周期的倒数第二步。可以看到这里,调用了 mLoaderManager.doDestroy().

onDetach()
@MainThread
@CallSuper
public void onDetach() {
    mCalled = true;
}

Fragment 生命周期的最后一个方法,当 Fragment 不再和一个 Activity 绑定时调用。 Fragment 的 onDestroyView() , onDestroy() , onDetach() 三个对应Activity 的 onDestroyed()方法。

fragment整体架构图

image.png

  • FragmentActivity 是 Activity 支持 Fragment 的基础,其中持有一个 FragmentController 中间类,它是 FragmentActivity 和 FragmentManager 的中间桥接者,对 Fragment 的操作最终是分发到 FragmentManager 来处理;
  • FragmentManager 承载了 Fragment 的核心逻辑,负责对 Fragment 执行添加、移除或替换等操作,以及添加到返回堆栈。它的实现类 FragmentManagerImpl 是我们主要的分析对象;
  • FragmentHostCallback 是 FragmentManager 向 Fragment 宿主的回调接口,Activity 和 Fragment 中都有内部类实现该接口,所以 Activity 和 Fragment 都可以作为另一个 Fragment 的宿主(Fragment 宿主和 FragmentManager 是 1 : 1 的关系);
  • FragmentTransaction 是 Fragment 事务抽象类,它的实现类BackStackRecord 是事务管理的主要分析对象。
宿主与关联的 FragmentManager 的关系

image.png

Fragment的五种状态

  • static final int INITIALIZING = 0; 初始状态,Fragment 未创建
  • static final int CREATED = 1; 已创建状态,Fragment 视图未创建
  • static final int ACTIVITY_CREATED = 2; 已视图创建状态,Fragment 不可见
  • static final int STARTED = 3; 可见状态,Fragment 不处于前台
  • static final int RESUMED = 4; 前台状态,可接受用户交互

事务

BackStackRecord 继承了 FragmentTransaction :

final class BackStackRecord extends FragmentTransaction implements
        FragmentManager.BackStackEntry, FragmentManager.OpGenerator {
        }

FragmentTransaction 定义了一系列对 Fragment 的操作方法:

//它会调用 add(int, Fragment, String),其中第一个参数传的是 0
public abstract FragmentTransaction add(Fragment fragment, String tag);

//它会调用 add(int, Fragment, String),其中第三个参数是 null
public abstract FragmentTransaction add(@IdRes int containerViewId,
Fragment fragment);

//添加一个 Fragment 给 Activity 的最终实现
//第一个参数表示 Fragment 要放置的布局 id
//第二个参数表示要添加的 Fragment,【注意】一个 Fragment 只能添加一次
//第三个参数选填,可以给 Fragment 设置一个 tag,后续可以使用这个 tag 查询它
public abstract FragmentTransaction add(@IdRes int containerViewId,
Fragment fragment,@Nullable String tag);

//调用 replace(int, Fragment, String),第三个参数传的是 null
public abstract FragmentTransaction replace(@IdRes int containerViewId,Fragment fragment);

//替换宿主中一个已经存在的 fragment
//这一个方法等价于先调用 remove(), 再调用 add()
public abstract FragmentTransaction replace(@IdRes int containerViewId,Fragment fragment,@Nullable String tag);

//移除一个已经存在的 fragment
//如果之前添加到宿主上,那它的布局也会被移除
public abstract FragmentTransaction remove(Fragment fragment);

//隐藏一个已存的 fragment
//其实就是将添加到宿主上的布局隐藏
public abstract FragmentTransaction hide(Fragment fragment);

//显示前面隐藏的 fragment,这只适用于之前添加到宿主上的 fragment
public abstract FragmentTransaction show(Fragment fragment);

//将指定的 fragment 将布局上解除
//当调用这个方法时,fragment 的布局已经销毁了
public abstract FragmentTransaction detach(Fragment fragment);

//当前面解除一个 fragment 的布局绑定后,调用这个方法可以重新绑定
//这将导致该 fragment 的布局重建,然后添加、展示到界面上
public abstract FragmentTransaction attach(Fragment fragment);

对 fragment 的操作基本就这几步,我们知道,要完成对 fragment 的操作,最后还需要提交一下.

事务的提交方式:

  • commit() 在主线程中异步执行,其实也是 Handler 抛出任务,等待主线程调度执行。
  • commitAllowingStateLoss() 异步执行,但它的不同之处在于,允许在 Activity 保存状态之后调用,也就是说它遇到状态丢失不会报错。
  • commitNow() 是同步执行的,立即提交任务。
  • commitNowAllowingStateLoss() 同步执行

我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿