Fragment(二)状态改变与管理

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

Fragment(二)状态改变与管理

博客对应的Demo地址:GitHubGitee

通过这篇博客,我们能知道以下问题:

  • FragmentmState 变化过程
  • FragmentManagermCurState 变化过程

在《Fragment(一)从源码角度看add和replace过程》中,我们知道了Fragment使用addreplace加载到页面的基本过程,最后是根据状态判断,然后调用对应的方法,但是并没有详细说明状态的变化过程,这篇文章我们就主要来说说这个过程。在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 整个生命周期的:
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 构造)简单总结

  1. 启动一个 FragmentActivity
  2. FragmentActivity中创建类型为 FragmentController 的成员变量 mFragments,创建这个对象的需要一个 HostCallbacks 对象,所以也会创建,在 HostCallbacks 的父类 FragmentHostCallback 中有一个类型为 FragmentManager 的成员变量 mFragmentManager 也会创建(具体为 FragmentManager 的子类 FragmentManagerImpl ),
  3. 调用构造和内部的 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() 方法,在这个方法的调用过程中会回调到 FragmentActivityonCreateView() 方法(这个调用过程在文章底部 “扩展:ActivityonCreateView() 方法的调用过程” 可以查看),在这个方法中又会调用到 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);
}

接着调用mFragmentsonCreateView() 方法,实际就是 FragmentController#onCreateView():

// FragmentController#onCreateView()
public View onCreateView(@Nullable View parent, @NonNull String name, @NonNull Context context,
        @NonNull AttributeSet attrs) {
    return mHost.mFragmentManager
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值