-
简书
-
CSDN
Fragment(二)状态改变与管理
通过这篇博客,我们能知道以下问题:
Fragment的mState变化过程FragmentManager的mCurState变化过程
在《Fragment(一)从源码角度看add和replace过程》中,我们知道了Fragment使用add和replace加载到页面的基本过程,最后是根据状态判断,然后调用对应的方法,但是并没有详细说明状态的变化过程,这篇文章我们就主要来说说这个过程。在Fragment 的整个生命周期中,主要的状态有两个,非别用 Fragment 自己的 mState 字段 和 FragmentManager 中的 mCurState 字段 表示。
说明和注意
因为不同的使用方式和不同的源码版本(android.support和androidX,或者非支持包中的Fragment)会有些差别,特对当前文章的使用方式和源码库版本进行声明。
-
1. 源码版本: AndroidX库,具体 androidx.fragment:1.3.4 版本
-
2. 使用方式:直接在对应
FragmentActivity的布局文件中使用<fragment>标签的方式// xml 布局中使用 fragment 标签,在 FragmentActivity 中调用 setContentView() 方法设置对应的布局id <fragment android:id="@+id/fragment_replace_default" android:name="com.renj.fragment.replace.ReplaceFragment1" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" />
取值常量
首先看看他们的取值有哪些,两个取值都是用的 Fragment 中的常量:
static final int INITIALIZING = -1; // Not yet attached. (默认,还依附定到容器)
static final int ATTACHED = 0; // Attached to the host. (依附到容器)
static final int CREATED = 1; // Created. (创建 Fragment)
static final int VIEW_CREATED = 2; // View Created.(Fragment 的视图创建)
static final int AWAITING_EXIT_EFFECTS = 3; // Downward state, awaiting exit effects (等待退出)
static final int ACTIVITY_CREATED = 4; // Fully created, not started.(完全创建,未启动)
static final int STARTED = 5; // Created and started, not resumed.(启动)
static final int AWAITING_ENTER_EFFECTS = 6; // Upward state, awaiting enter effects(等待进入)
static final int RESUMED = 7; // Created started and resumed.(创建开始并恢复/可操作)
Fragment状态值和生命周期对应关系图
我们发现状态与我们的政策生命周期有些对不上,比如 Pause、Destory 等状态都没有对应的值,我们先通过一张图来看看它们是怎样表示 Fragment 整个生命周期的:

具体分析
我们一般使用的都是支持包(android.support或者 androidX,这篇博客主要以AndroidX为目标)中的Fragment,所以 Activity 就应该是 FragmentActivity 或者其子类,我们主要通过FragmentActivity的生命周期变化来看对应的Fragment的状态变化。如果想要了解 Activity 的生命周期过程,请移步 《简书:Activity 的组成》 、 《CSDN:Android自定义View之Activity页面的组成》 ,查看相关内容。
FragmentActivity 构造
首先我们从 FragmentActivity 的构造方法开始看
// 定义 mFragments
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
public FragmentActivity() {
super();
init();
}
@ContentView
public FragmentActivity(@LayoutRes int contentLayoutId) {
super(contentLayoutId);
init();
}
private void init() {
// 增加Context与FragmentActivity关联时的回调监听
addOnContextAvailableListener(new OnContextAvailableListener() {
@Override
public void onContextAvailable(@NonNull Context context) {
// 调用 FragmentController 的 attachHost() 方法
mFragments.attachHost(null /*parent*/);
Bundle savedInstanceState = getSavedStateRegistry()
.consumeRestoredStateForKey(FRAGMENTS_TAG);
if (savedInstanceState != null) {
// 用于恢复状态
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
mFragments.restoreSaveState(p);
}
}
});
}
查看 FragmentController#attachHost() 实现:
public void attachHost(@Nullable Fragment parent) {
mHost.mFragmentManager.attachController(
mHost, mHost /*container*/, parent);
}
内部没有做什么实质性的操作, 它就是一个中间层,调用 FragmentManager#attachController() 方法:
void attachController(@NonNull FragmentHostCallback<?> host,
@NonNull FragmentContainer container, @Nullable final Fragment parent) {
if (mHost != null) throw new IllegalStateException("Already attached");
mHost = host;
mContainer = container;
mParent = parent;
// ... 注册各种监听,省略
}
在方法中,除了赋值以外,就是注册各种监听,并无其他实际操作, 这里的 mHost 就是 FragmentActivity 内部类 HostCallbacks, mContainer 就是没有做什么实质工作的 FragmentContainer,这里直接也是使用的 mHost(因为 HostCallbacks 间接继承了 FragmentContainer), mParent 指的是要依附的 Fragment, 当前的过程是 Activity 驱动的, 所以不存在 Fragment, 该值为 null。
目前步骤(FragmentActivity 构造)简单总结:
- 启动一个
FragmentActivity- 在
FragmentActivity中创建类型为FragmentController的成员变量mFragments,创建这个对象的需要一个HostCallbacks对象,所以也会创建,在HostCallbacks的父类FragmentHostCallback中有一个类型为FragmentManager的成员变量mFragmentManager也会创建(具体为FragmentManager的子类FragmentManagerImpl),- 调用构造和内部的
init()方法,进而调用FragmentController#attachHost()方法,最终调用FragmentManager#attachController()方法,将相关值传递到FragmentManager中
接着看 FragmentActivity 中与 Fragment 相关的下一步回调
FragmentActivity#onCreate() 方法
onCreate() 方法表示 Activity 创建,在这个方法中我们会调用 setContentView() 方法设置页面布局,在 setContentView() 这个方法中会,会调用一个与Fragment相关的方法,我们看一下FragmentActivity#onCreate() 方法:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
mFragments.dispatchCreate();
}
先调用 super.onCreate() 方法,然后调用 mFragments.dispatchCreate()(也就是FragmentController#dispatchCreate()),而在我们自己的 Activity 中会调用 setContentView() 方法,在这个方法的调用过程中会回调到 FragmentActivity 的 onCreateView() 方法(这个调用过程在文章底部 “扩展:Activity 中 onCreateView() 方法的调用过程” 可以查看),在这个方法中又会调用到 Fragment 中的相关方法。我们看看 FragmentActivity#onCreateView() 方法:
@Override
@Nullable
public View onCreateView(@Nullable View parent, @NonNull String name, @NonNull Context context,
@NonNull AttributeSet attrs) {
final View v = dispatchFragmentsOnCreateView(parent, name, context, attrs);
if (v == null) {
return super.onCreateView(parent, name, context, attrs);
}
return v;
}
@Nullable
final View dispatchFragmentsOnCreateView(@Nullable View parent, @NonNull String name,
@NonNull Context context, @NonNull AttributeSet attrs) {
return mFragments.onCreateView(parent, name, context, attrs);
}
接着调用mFragments的onCreateView() 方法,实际就是 FragmentController#onCreateView():
// FragmentController#onCreateView()
public View onCreateView(@Nullable View parent, @NonNull String name, @NonNull Context context,
@NonNull AttributeSet attrs) {
return mHost.mFragmentManager.getLayoutInflaterFactory()
.onCreateView(parent, name, context, attrs);
}
看看 FragmentManager#getLayoutInflaterFactory() 返回的是什么:

本文详细探讨了Fragment在Android应用中的状态改变与管理,包括状态值和生命周期的对应关系,以及在不同状态间转换的具体流程。通过分析源码,揭示了Fragment从创建到显示、关闭时的状态变化,重点讲解了关键方法如onCreate、onCreateView、onStart、onResume等的调用顺序和影响。同时,文中还讨论了Fragment与Activity状态的联动,以及在不同场景下的状态保存和恢复策略。
最低0.47元/天 解锁文章
1512

被折叠的 条评论
为什么被折叠?



