Fragment状态改变与管理
Posted ITRenj
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Fragment状态改变与管理相关的知识,希望对你有一定的参考价值。
-
简书
-
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()
返回的是什么:
@NonNull
LayoutInflater.Factory2 getLayoutInflaterFactory()
return mLayoutInflaterFactory;
// FragmentManager 的成员变量
private final FragmentLayoutInflaterFactory mLayoutInflaterFactory =
new FragmentLayoutInflaterFactory(this);
这里返回的 FragmentManager
中定义的一个成员变量 mLayoutInflaterFactory
,具体的类型是 FragmentLayoutInflaterFactory
,所以我们接着看 FragmentLayoutInflaterFactory#onCreateView()
方法:
@Override
public View onCreateView(@Nullable final View parent, @NonNull String name,
@NonNull Context context, @NonNull AttributeSet attrs)
// ...
// 设置 Fragment 成员变量 mFromLayout 和 mInLayout 的值为 true
fragment.mFromLayout = true;
fragment.mInLayout = true;
// 1. 将 Fragment 添加到 mAdded 中
fragmentStateManager = mFragmentManager.addFragment(fragment);
// ...
fragment.mContainer = (ViewGroup) parent;
// 2. 修改Fragment状态并调用相关方法
fragmentStateManager.moveToExpectedState();
// 3. 继续调用相关回调方法
fragmentStateManager.ensureInflatedView();
// ...
return fragment.mView;
1. FragmentManager.addFragment(fragment)
源码追踪:
// FragmentManager.addFragment(fragment)
FragmentStateManager addFragment(@NonNull Fragment fragment)
FragmentStateManager fragmentStateManager = createOrGetFragmentStateManager(fragment);
// 调用 FragmentStore#addFragment(fragment)
mFragmentStore.addFragment(fragment);
return fragmentStateManager;
// FragmentStore#addFragment(fragment)
void addFragment(@NonNull Fragment fragment)
synchronized (mAdded)
mAdded.add(fragment);
fragment.mAdded = true;
将当前的 Fragment
加入到 FragmentStore#mAdded
中,如果熟悉了《简书:Fragment(一)从源码角度看add和replace过程》、《CSDN:Fragment(一)从源码角度看add和replace过程》这篇博客,对这个列表就不会感到陌生了,这里就不多说了。
2. FragmentStateManager.moveToExpectedState()
源码追踪:
void moveToExpectedState()
// 调用 computeExpectedState() 计算应该处于的状态值
while ((newState = computeExpectedState()) != mFragment.mState)
// Fragment 打开
if (newState > mFragment.mState)
// Moving upward
int nextStep = mFragment.mState + 1;
switch (nextStep)
case Fragment.ATTACHED:
attach();
break;
case Fragment.CREATED:
create();
break;
case Fragment.VIEW_CREATED:
ensureInflatedView();
createView();
break;
case Fragment.AWAITING_EXIT_EFFECTS:
activityCreated();
break;
case Fragment.ACTIVITY_CREATED:
if (mFragment.mView != null && mFragment.mContainer != null)
SpecialEffectsController controller = SpecialEffectsController
.getOrCreateController(mFragment.mContainer,
mFragment.getParentFragmentManager());
int visibility = mFragment.mView.getVisibility();
SpecialEffectsController.Operation.State finalState =
SpecialEffectsController.Operation.State.from(visibility);
controller.enqueueAdd(finalState, this);
mFragment.mState = Fragment.ACTIVITY_CREATED;
break;
case Fragment.STARTED:
start();
break;
case Fragment.AWAITING_ENTER_EFFECTS:
mFragment.mState = Fragment.AWAITING_ENTER_EFFECTS;
break;
case Fragment.RESUMED:
resume();
break;
else
// Fragment 关闭
调用 computeExpectedState()
方法计算 Fragment
当前应该的状态值,如果当前的状态值与应该的状态值不一样,那么就进入循环,获取下一步的状态,然后调用相关方法,直到当前状态处于应该的状态。
注意:这里我将 else
部分的代码去掉了,因为在前面的分析是不会走到里面去的。在 Fragment
创建到显示的过程当中 newState > mFragment.mState
条件是一定成立的。else
的代码主要在 Fragment
退出的时候。在后面会放出来。
默认 Fragment#mState
的状态是 Fragment.INITIALIZING
的,但是走到这一步的时候,computeExpectedState()
方法计算出应该的状态值是 Fragment.VIEW_CREATED
的(具体的计算过程就不看贴出来,想详细了解的话可以通过debug的方式一步一步查看)。两个值不一样,所以需要进入循环:
- 第一次进入循环:
Fragment#mState
的值为Fragment.INITIALIZING
-> 计算出的应该值为Fragment.VIEW_CREATED
->if
条件成立 ->nextStep
的值为Fragment.mState+1
,也就是Fragment.ATTACHED
-> 进而调用FragmentStateManager#attach()
方法 ->Fragment#performAttach()
【在这个方法中会将Fragment#mState
的值修改为Fragment.ATTACHED
并且调用Fragment#onAttach()
方法 】 - 当前的值变为
Fragment.ATTACHED
后,继续循环计算和判断,第二次计算出的值还是Fragment.VIEW_CREATED
,与当前的不一样,进而进入if
->nextStep
的值为Fragment.mState+1
,也就是Fragment.CREATED
-> 进而调用FragmentStateManager#create()
方法 ->Fragment#performCreate()
【在这个方法中会将Fragment#mState
的值修改为Fragment.CREATED
并且调用Fragment#onCreate()
方法 】 - 当前的值变为
Fragment.CREATED
后,继续循环计算和判断,第三次计算出的值还是Fragment.VIEW_CREATED
,与当前的不一样,进而进入if
->nextStep
的值为Fragment.mState+1
,也就是Fragment.VIEW_CREATED
-> 进而调用FragmentStateManager#ensureInflatedView()
方法 和FragmentStateManager#createView()
方法FragmentStateManager#ensureInflatedView()
【在这个方法中会将Fragment#mState
的值修改为Fragment.VIEW_CREATED
】 ->Fragment#performViewCreated()
【在这个方法中会将mPerformedCreateView
变量设置成true,并且调用Fragment#onViewCreated()
方法 】FragmentStateManager#createView()
这个方法的主要作用也是创建Fragment
的View
,并且将Fragment
的状态修改为Fragment.VIEW_CREATED
并且回调对应的方法,但是在这里会直接返回,因为在前一步已经把Fragment
的View
创建完成了,并且状态值也修改成对应的了。
当循环到这里时,当前状态已经和计算出的应该状态一样了,循环结束,FragmentStateManager.moveToExpectedState()
流程结束,接着往下看。
3. FragmentStateManager#ensureInflatedView()
源码追踪:
// FragmentStateManager#ensureInflatedView()
void ensureInflatedView()
if (mFragment.mFromLayout && mFragment.mInLayout && !mFragment.mPerformedCreateView)
if (FragmentManager.isLoggingEnabled(Log.DEBUG))
Log.d(TAG, "moveto CREATE_VIEW: " + mFragment);
mFragment.performCreateView(mFragment.performGetLayoutInflater(
mFragment.mSavedFragmentState), null, mFragment.mSavedFragmentState);
if (mFragment.mView != null)
mFragment.mView.setSaveFromParentEnabled(false);
mFragment.mView.setTag(R.id.fragment_container_view_tag, mFragment);
if (mFragment.mHidden) mFragment.mView.setVisibility(View.GONE);
mFragment.performViewCreated();
mDispatcher.dispatchOnFragmentViewCreated(
mFragment, mFragment.mView, mFragment.mSavedFragmentState, false);
mFragment.mState = Fragment.VIEW_CREATED;
这一步同样是为了保证将 Fragment
的状态到相应值,并且回调对应方法。这里在进行 if
判断时不满足,因为第三个判断 mFragment.mPerformedCreateView
的值在上面的 Fragment#performViewCreated()
方法中已经设置为 true
了,所以 if
条件不满足,直接跳过。到此为止,Activity#setContentView()
影响 Fragment
的部分基本完成。
关于 FragmentActivity#onCreate()
的疑问
-
为什么
FragmentActivity#onCreate()
中的mFragments.dispatchCreate();
方法 先调用,但是没有执行Fragment
的相关方法?使用
fragment
标签时,虽然FragmentActivity#onCreate()
方法中的mFragments.dispatchCreate();
会比setContentView()
先调用,但是这个时候Fragment
还没有加载到FragmentStore#mAdded
中,所以它本身不会回调Fragment
相关的方法。我们通过上面的分析知道了Fragment
的增加是在FragmentLayoutInflaterFactory#onCreateView()
方法中,也就是fragment
创建完成时回调FragmentActivity#onCreateView()
方法的过程中增加的。看一下mFragments.dispatchCreate()
的调用过程:FragmentController#dispatchCreate()
->FragmentManager#dispatchCreate()
->FragmentManager#dispatchStateChange(Fragment.CREATED)
->FragmentManager#moveToState()
->FragmentStore#moveToExpectedState()
->FragmentStateManager#moveToExpectedState()
// FragmentManager#moveToState() void moveToState(int newState, boolean always) // 修改FragmentManager 的 mCurState 字段值为新状态,这里也就是 Fragment.CREATED mCurState = newState; // 调用 FragmentStore#moveToExpectedState() mFragmentStore.moveToExpectedState(); // FragmentStore#moveToExpectedState() void moveToExpectedState() for (Fragment f : mAdded) FragmentStateManager fragmentStateManager = mActive.get(f.mWho); if (fragmentStateManager != null) fragmentStateManager.moveToExpectedState(); // ...
在这个方法中遍历了
mAdded
列表,然后调用FragmentStateManager#moveToExpectedState()
方法进而回调Fragment
的相关方法,但是现在mAdded
还是空的,所以不会调用相关方法。
到这里,Activity
方法的 onCreate()
方法执行完成了。
我们对这一步(FragmentActivity#onCreate()
方法)进行一个简单总结:
- 在
onCreate()
中调用mFragments.dispatchCreate()
,但是这个方法不会回调到Fragmnet
的相关方法,因为现在fragmnet
标签还没解析到,不过会将FragmentManager
的mCurState
字段值设置为Fragment.CREATED
。- 在调用
setContentView()
的过程中会通过一系列的调用,最终回调Fragment
的Fragment#onAttach()
、Fragment#onCreate()
、Fragment#onViewCreated()
,并且Fragment
的状态值mState
会变为Fragment.VIEW_CREATED
,具体的变化:Fragment.INITIALIZING
->Fragment.ATTACHED
->Fragment.CREATED
->Fragment.VIEW_CREATED
FragmentActivity#onStart()
方法
Activity
的onCreate()
方法执行完之后,系统回调的下一个生命周期方法是 onStart()
,我们看一下 FragmentActivity
的 onStart()
方法:
@Override
protected void onStart()
super.onStart();
mStopped = false;
if (!mCreated)
mCreated = true;
// 1. 调用 dispatchActivityCreated() 方法
mFragments.dispatchActivityCreated();
// 2. 调用 dispatchStart() 方法
mFragments.dispatchStart();
主要是通过 mFragments(FragmentController)
调用了dispatchActivityCreated()
和 dispatchStart()
两个方法。
1. FragmentController#dispatchActivityCreated()
方法
源码追踪:
// FragmentController#dispatchActivityCreated()
public void dispatchActivityCreated()
mHost.mFragmentManager.dispatchActivityCreated();
// FragmentManager#dispatchActivityCreated()
void dispatchActivityCreated()
mStateSaved = false;
mStopped = false;
mNonConfig.setIsStateSaved(false);
dispatchStateChange(Fragment.ACTIVITY_CREATED);
// FragmentManager#dispatchStateChange()
private void dispatchStateChange(int nextState)
// ...
// 设置/修改 FragmentStateManager#mFragmentManagerState 的值
mFragmentStore.dispatchStateChange(nextState);
// ...
// 调用 FragmentManager#moveToState() 方法,这个方法
moveToState(nextState, false);
// FragmentManager#moveToState()
void moveToState(int newState, boolean always)
// 修改FragmentManager 的 mCurState 字段值为新状态,这里也就是 Fragment.CREATED
mCurState = newState;
// 调用 FragmentStore#moveToExpectedState()
mFragmentStore.moveToExpectedState();
通过源码我们发现调用到了 FragmentManager#moveToState()
方法,在这个方法中对 FragmentManager
的 mCurState
字段值进行了修改,这里就是设置值为 Fragment.ACTIVITY_CREATED
了;接着调用 FragmentStore#moveToExpectedState()
方法,这个方法的内部主要就是循环计算和判断当前状态值与计算出来的应该值是否一样,进而调用对应的方法。这一步计算出来的应该的值是 Fragment.ACTIVITY_CREATED
,所以 Fragment
的 mState
值将会变为 Fragment.AWAITING_EXIT_EFFECTS
然后变为 Fragment.ACTIVITY_CREATED
,在这个过程中会调用 FragmentStateManager#activityCreated()
,进而调用 Fragment#performActivityCreated()
-> Fragment#onActivityCreated()
回调。
2. FragmentController#dispatchStart()
方法
这个方法的调用过程和FragmentController#dispatchActivityCreated()
方法类似,就不再将源码都贴出来了,它主要通过 dispatchStateChange(Fragment.STARTED);
方法将FragmentManager
的 mCurState
字段值设置为 Fragment.STARTED
,然后通过 FragmentStore.moveToExpectedState()
方法进行循环判断,这一步将 Fragment
的状态设置成了 Fragment.STARTED
,在这个过程中会调用 FragmentStateManager#start()
,进而调用 Fragment#performStart()
-> Fragment#onStart()
回调。
我们对这一步(FragmentActivity#onStart()
方法)进行一个简单总结:
- 在
onStart()
中调用dispatchActivityCreated()
和dispatchStart()
两个方法;dispatchActivityCreated()
方法将FragmentManager#mCurState
的值由上一步的Fragment.CREATED
变为Fragment.ACTIVITY_CREATED
;并且将Fragment#mState
的值改变,具体变化过程为:Fragment.VIEW_CREATED
->Fragment.AWAITING_EXIT_EFFECTS
->Fragment.ACTIVITY_CREATED
;dispatchStart()
方法将FragmentManager#mCurState
的值由上一步的Fragment.ACTIVITY_CREATED
变为Fragment.STARTED
;并且将Fragment#mState
的值改变,具体变化过程为:Fragment.ACTIVITY_CREATED
->Fragment.STARTED
;
FragmentActivity#onResume()
方法
Activity
的onCreate()
方法执行完之后,系统回调的下一个生命周期方法是 onResume()
,我们看一下 FragmentActivity
的 onResume()
方法:
protected void onResume()
super.onResume();
mResumed = true;
mFragments.noteStateNotSaved();
mFragments.execPendingActions();
我们发现并没有调用类似 dispatchXxx()
的方法,那么我们接着往上一层代码看,Activity#onResume()
方法的调用是在 Activity#performResume()
方法进而调用 Instrumentation#callActivityOnResume(this)
方法,在这个方法中 Activity#onResume()
方法被回调。那么我们先看一下 Activity#performResume()
:
final void performResume(boolean followedByPause, String reason)
// 回调 Activity 的 onResume() 方法
mInstrumentation.callActivityOnResume(this);
// 看上去就是调用了我们熟悉的方法,然后回调Fragment的方法
mFragments.dispatchResume();
// 调用 onPostResume() 方法
onPostResume();
调用 mFragments.dispatchResume();
了这个方法,这个方法看上去就是我们需要的,但是我们会发现这个因为是在 Activity
中调用,而不是 FragmentActivity
中调用,那么它使用的就是 android.app
包,所以不是我们需要的。
进而看一下 Activity#onPostResume()
方法:
// Activity#onPostResume()
protected void onPostResume()
final Window win = getWindow();
if (win != null) win.makeActive();
if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(true);
mCalled = true;
好像没有找到我们需要的,但是这是 Activity
中实现,我们发现 FragmentActivity
中重写了这个方法:
// FragmentActivity#onPostResume()
protected void onPostResume()
super.onPostResume();
onResumeFragments();
// FragmentActivity#onResumeFragments()
protected void onResumeFragments()
mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
mFragments.dispatchResume();
通过查看源码发现最终在 FragmentActivity#onResumeFragments()
方法中找到了我们需要的方法 mFragments.dispatchResume()
。前面已经对类似的方法说过好几次了,所以就不在一步一步看源码了,直接做一个总结。
我们对这一步(FragmentActivity#onResume()
方法)进行一个简单总结:
- 在
FragmentActivity#onResume()
中并没有调用mFragments.dispatchResume()
方法,而是在FragmentActivity#onResumeFragments()
中调用的。dispatchResume()
方法执行过程中会将FragmentManager#mCurState
的值由上一步的Fragment.STARTED
变为Fragment.RESUMED
;并且将Fragment#mState
的值改变,具体变化过程为:Fragment.STARTED
->Fragment.AWAITING_ENTER_EFFECTS
->Fragment.RESUMED
。
到这一步执行完成,我们的 Fragment
就已经完全显示,并且用户可操作了。
关闭 Fragment
时 mState
的变化过程
在文章开头时,我们将它的取值贴出来了,发现到了 RESUME
就没有了,那么我先关闭时 Activity
调用 onPause()
、 onStop()
、 onDestory()
时,Fragment#mState
的变化过程又是什么样,它们又用哪些值来表示呢?我们接着往下看。
FragmentActivity#onPause()
方法
源码追踪:
// FragmentActivity#onPause()
protected void onPause()
super.onPause();
mResumed = false;
mFragments.dispatchPause();
mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
// FragmentController#dispatchPause()
public void dispatchPause()
mHost.mFragmentManager.dispatchPause();
// FragmentManager#dispatchPause()
void dispatchPause()
dispatchStateChange(Fragment.STARTED);
通过方法追踪我们发现调用 FragmentActivity#onPause()
方法后状态值又是传递的 Fragment.STARTED
,通过调用最终方法肯定会走到 FragmentStateManager#moveToExpectedState()
方法,通过上面的分析我们应该都很熟悉了,所以中间的调用过程就不贴出来了。
void moveToExpectedState()
mMovingToState = true;
int newState;
while ((newState = computeExpectedState()) != mFragment.mState)
if (newState > mFragment.mState)
// Fragment 进入
else
// Fragment 退出
int nextStep = mFragment.mState - 1;
switch (nextStep)
case Fragment.AWAITING_ENTER_EFFECTS:
pause();
break;
case Fragment.STARTED:
mFragment.mState = Fragment.STARTED;
break;
case Fragment.ACTIVITY_CREATED:
stop();
break;
case Fragment.AWAITING_EXIT_EFFECTS:
if (FragmentManager.isLoggingEnabled(Log.DEBUG))
Log.d(TAG, "movefrom ACTIVITY_CREATED: " + mFragment);
if (mFragment.mView != null)
// Need to save the current view state if not done already
// by saveInstanceState()
if (mFragment.mSavedViewState == null)
saveViewState();
if (mFragment.mView != null && mFragment.mContainer != null)
SpecialEffectsController controller = SpecialEffectsController
.getOrCreateController(mFragment.mContainer,
mFragment.getParentFragmentManager());
controller.enqueueRemove(this);
mFragment.mState = Fragment.AWAITING_EXIT_EFFECTS;
break;
case Fragment.VIEW_CREATED:
mFragment.mInLayout = false;
mFragment.mState = Fragment.VIEW_CREATED;
break;
case Fragment.CREATED:
destroyFragmentView();
mFragment.mState = Fragment.CREATED;
break;
case Fragment.ATTACHED:
destroy();
break;
case Fragment.INITIALIZING:
detach();
break;
之前的过程已经将 if
当中的流程说了,所以这里就将哪些代码去掉了;通过之前的分析我们已经知道了 Fragment#mState
的值是 RESUMED
了,已经是取值范围中最大的了,所以 if
条件 if (newState > mFragment.mState)
肯定是不成立的了。现在只剩下 else
的代码,因为在 Fragment
退出的过程当中,走的都是 else
当中的代码。
在 computeExpectedState()
方法计算出的应该值是 Fragment.STARTED
,和当前的 Fragment.RESUME
不一样,所以进入循环,这一步会经过两次循环:
case Fragment.AWAITING_ENTER_EFFECTS:
pause();
break;
case Fragment.STARTED:
mFragment.mState = Fragment.STARTED;
break;
// FragmentStateManager#pause()
void pause()
mFragment.performPause();
mDispatcher.dispatchOnFragmentPaused(mFragment, false);
// Fragment#performPause()
void performPause()
mState = AWAITING_ENTER_EFFECTS;
mCalled = false;
onPause();
通过源码已经看得非常清晰了,我们直接对这一步(FragmentActivity#onPause()
方法)进行一个简单总结:
- 在
FragmentActivity#onPause()
中调用mFragments.dispatchPause()
方法。dispatchPause()
方法执行过程中会将FragmentManager#mCurState
的值由上一步的Fragment.RESUMED
变为Fragment.STARTED
;并且将Fragment#mState
的值改变,具体变化过程为:Fragment.RESUMED
->Fragment.AWAITING_ENTER_EFFECTS
->Fragment.STARTED
,然后回调Fragment#onPause()
方法。
FragmentActivity#onStop()
方法
源码追踪:
// FragmentActivity#onStop()
protected void onStop()
super.onStop();
mFragments.dispatchStop();
// FragmentController#dispatchStop()
public void dispatchStop()
mHost.mFragmentManager.dispatchStop();
// FragmentManager#dispatchStop()
void dispatchStop()
mStopped = true;
mNonConfig.setIsStateSaved(true);
dispatchStateChange(Fragment.ACTIVITY_CREATED);
通过方法追踪: FragmentActivity#onStop()
方法后状态值传递的 Fragment.ACTIVITY_CREATED
,通过调用最终方法肯定会走到 FragmentStateManager#moveToExpectedState()
方法,通过上面的分析我们应该都很熟悉了,所以中间的调用过程就不贴出来了。
在 computeExpectedState()
方法计算出的应该值是 Fragment.ACTIVITY_CREATED
,和当前的 Fragment.STARTED
不一样,所以进入循环,这一步会经过一次循环:
case Fragment.ACTIVITY_CREATED:
stop();
break;
// FragmentStateManager#stop()
void stop()
mFragment.performStop();
mDispatcher.dispatchOnFragmentStopped(mFragment, false);
// Fragment#performStop()
void performStop()
mState = ACTIVITY_CREATED;
mCalled = false;
onStop();
调用之后再次计算,还是一样的值,所以不在进入循环。
通过源码已经看得非常清晰了,我们直接对这一步(FragmentActivity#onStop()
方法)进行一个简单总结:
- 在
FragmentActivity#onStop()
中调用mFragments.dispatchPause()
方法。dispatchPause()
方法执行过程中会将FragmentManager#mCurState
的值由上一步的Fragment.STARTED
变为Fragment.ACTIVITY_CREATED
;并且将Fragment#mState
的值改变,具体变化过程为:Fragment.STARTED
->Fragment.ACTIVITY_CREATED
,然后回调Fragment#onStop()
方法。
FragmentActivity#onDestroy()
方法
源码追踪:
// FragmentActivity#onDestroy()
protected void onDestroy()
super.onDestroy();
mFragments.dispatchDestroy();
// FragmentController#dispatchDestroy()
public void dispatchDestroy()
mHost.mFragmentManager.dispatchDestroy();
// FragmentManager#dispatchDestroy()
void dispatchDestroy()
mDestroyed = true;
mNonConfig.setIsStateSaved(true);
dispatchStateChange(Fragment.INITIALIZING);
通过方法追踪: FragmentActivity#onDestroy()
方法后状态值传递的 Fragment.INITIALIZING
,通过调用最终方法肯定会走到 FragmentStateManager#moveToExpectedState()
方法,通过上面的分析我们应该都很熟悉了,所以中间的调用过程就不贴出来了。
在 computeExpectedState()
方法计算出的应该值是 Fragment.VIEW_CREATED
,和当前的 Fragment.ACTIVITY_CREATED
不一样,所以进入循环,这一步会经过多次循环:
case Fragment.AWAITING_EXIT_EFFECTS:
if (FragmentManager.isLoggingEnabled(Log.DEBUG))
Log.d(TAG, "movefrom ACTIVITY_CREATED: " + mFragment);
if (mFragment.mView != null)
// Need to save the current view state if not done already
// by saveInstanceState()
if (mFragment.mSavedViewState == null)
saveViewState();
if (mFragment.mView != null && mFragment.mContainer != null)
SpecialEffectsController controller = SpecialEffectsController
.getOrCreateController(mFragment.mContainer,
mFragment.getParentFragmentManager());
controller.enqueueRemove(this);
mFragment.mState = Fragment.AWAITING_EXIT_EFFECTS;
break;
case Fragment.VIEW_CREATED:
mFragment.mInLayout = false;
mFragment.mState = Fragment.VIEW_CREATED;
break;
这几次循环主要修改了 Fragment#mState
的值,并没有回调相关的生命周期方法,每一次循环结束后,都会继续进行计算当前应该的值然后判断,当Fragment#mState
的值变为 Fragment.VIEW_CREATED
后的下一次循环,计算出应该的值是 Fragment.INITIALIZING
,与当前值不一样,所以继续循环:
case Fragment.CREATED:
destroyFragmentView();
mFragment.mState = Fragment.CREATED;
break;
case Fragment.ATTACHED:
destroy();
break;
case Fragment.INITIALIZING:
detach();
break;
经历这几次循环时会调用多个和 Fragment
生命周期相关的方法,我们一个一个来看,他们时怎样修改各种状态的。
1. FragmentStateManager#destroyFragmentView()
// FragmentStateManager#destroyFragmentView()
void destroyFragmentView()
// 移除Fragment 的 View
if (mFragment.mContainer != null && mFragment.mView != null)
mFragment.mContainer.removeView(mFragment.mView);
// 调用 Fragment 的 performDestroyView() 方法
mFragment.performDestroyView();
// 将一些值设置为初始值
mFragment.mContainer = null;
mFragment.mView = null;
mFragment.mViewLifecycleOwner = null;
mFragment.mViewLifecycleOwnerLiveData.setValue(null);
mFragment.mInLayout = false;
// 主要看 Fragment#performDestroyView()
void performDestroyView()
// 设置 mState 的值为 CREATE
mState = CREATED;
mCalled = false;
// 回调 Fragment#onDestroyView() 方法
onDestroyView();
通过FragmentStateManager#destroyFragmentView()
方法的调用,会将 Fragment#mState
的值由 Fragment.VIEW_CREATED
变为 Fragment.CREATED
,并回调 Fragment#onDestroyView()
方法。
2. FragmentStateManager#destroy()
// FragmentStateManager#destroy()
void destroy()
if (shouldDestroy)
mFragment.performDestroy();
else
mFragment.mState = Fragment.ATTACHED;
判断是否需要调用 onDestory()
方法,如果不需要就直接修改状态值为 Fragment.ATTACHED
,这里当然是需要的,我们看继续看一下 Fragment#performDestroy()
方法:
// Fragment#performDestroy()
void performDestroy()
// 修改 mState 的值
mState = ATTACHED;
// 初始化部分成员变量
mCalled = false;
mIsCreated = false;
// 回调 Fragment 的 onDestroy() 方法
onDestroy();
通过FragmentStateManager#performDestroy()
方法的调用,会将 Fragment#mState
的值由 Fragment.CREATED
变为 Fragment.ATTACHED
,并回调 Fragment#onDestroy()
方法。
3. FragmentStateManager#detach()
// FragmentStateManager#detach()
void detach()
// 调用 Fragment#performDetach() 方法
mFragment.performDetach();
// 修改 mState 的值
mFragment.mState = Fragment.INITIALIZING;
// 初始化部分成员变量
mFragment.mHost = null;
mFragment.mParentFragment = null;
mFragment.mFragmentManager = null;
// Fragment#performDetach()
void performDetach()
mState = INITIALIZING;
mCalled = false;
// 回调 Fragment 的 onDetach() 方法
onDetach();
mLayoutInflater = null;
通过FragmentStateManager#detach()
方法的调用,会将 Fragment#mState
的值由 Fragment.ATTACHED
变为 Fragment.INITIALIZING
,并回调 Fragment#onDetach()
方法。
通过上面三个步骤的分析,对这一步(FragmentActivity#onDestroy()
方法)进行一个简单总结:
- 在
FragmentActivity#onDestroy()
中调用mFragments.dispatchPause()
方法。dispatchPause()
方法执行过程中会将FragmentManager#mCurState
的值由上一步的Fragment.ACTIVITY_CREATED
先变为Fragment.CREATED
,再变为Fragment.INITIALIZING
;- 通过方法调用改变
Fragment#mState
的值,具体的变化为:Fragment.ACTIVITY_CREATED
->Fragment.AWAITING_EXIT_EFFECTS
->Fragment.VIEW_CREATED
->Fragment.CREATED
->Fragment.ATTACHED
->Fragment.INITIALIZING
,然后回调Fragment#onDestroyView()
、Fragment#onDestroy()
、Fragment#onDetach()
方法。
总结
通过上一步的分析,我们已经知道了 Activity
的生命周期变化时怎样影响 Fragment
的对应的生命周期方法回调的,如果是 Fragment
嵌套 Fragment
的也是类似,是通过父 Fragment
影响子 Fragment
的,具体就是在 Fragment
的 performXxx()
方法中调用 FragmentManager
的方法,我们在这里随便看几个:
// Fragment#performDestroy()
void performDestroy()
// 通过FragmentManager改变子Fragment的状态和回调对应方法
mChildFragmentManager.dispatchDestroy();
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
mState = ATTACHED;
mCalled = false;
mIsCreated = false;
onDestroy();
// Fragment#performDetach()
void performDetach()
mState = INITIALIZING;
mCalled = false;
onDetach();
mLayoutInflater = null;
// 通过FragmentManager改变子Fragment的状态和回调对应方法
if (!mChildFragmentManager.isDestroyed())
mChildFragmentManager.dispatchDestroy();
mChildFragmentManager = new FragmentManagerImpl();
其他的就不再一个一个贴出来看了,都是一样或者类似的。
分析到这里,我们对于Fragment
的状态变化应该已经有了一个比较清晰的认知了。最后在来重新看一下上面的图
扩展:Activity
中 onCreateView()
方法的调用过程
从《简书:Android inflate解析》、《CSDN:Android inflate解析》文章中,我们知道LayoutInflater
对象最终都是通过getSystemService()
方法获取的。而这个方法关于 LayoutInflater
的实现是在 ContextThemeWrapper
类中,查看一下这个方法:
// 这个定义在 Context 中
public static final String LAYOUT_INFLATER_SERVICE = "layout_inflater";
// ContextThemeWrapper#getSystemService()
if (LAYOUT_INFLATER_SERVICE.equals(name))
if (mInflater == null)
mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
return mInflater;
return getBaseContext().getSystemService(name);
这个方法判断了我们所需要获取的 name
,而 LAYOUT_INFLATER_SERVICE
正是我们获取LayoutInflater
对象的名,所以会进入 if
条件中,LayoutInflater.from(getBaseContext())
方法也是返回 LayoutInflater
对象,但是这里再次调用了 LayoutInflater#cloneInContext()
方法,我们看一下这个方法的定义
public abstract LayoutInflater cloneInContext(Context newContext);
是一个抽象方法,那我们找一下它的实现方法,发现通过 Android studio 找不到,而通过debug的形式发现具体的类是 PhoneLayoutInflater
,我们直接查找系统源码看一下这个类:
/**
* @hide
*/
public class PhoneLayoutInflater extends LayoutInflater
private static final String[] sClassPrefixList =
"android.widget.",
"android.webkit.",
"android.app."
;
@Override protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException
for (String prefix : sClassPrefixList)
View view = createView(name, prefix, attrs);
if (view != null)
return view;
return super.onCreateView(name, attrs);
public LayoutInflater cloneInContext(Context newContext)
return new PhoneLayoutInflater(this, newContext);
已省略部分代码,但是核心代码就是这么简单。发现这个类在源码中用 @hide
标记了,所以在Android studio中不能直接点击找到。他确实继承了 LayoutInflater
类,方法 cloneInContext()
就是返回了本类对象,那也就是说我们在使用 LayoutInflater
类时实际上使用的是 PhoneLayoutInflater
类。
调用 setContentView()
到调用 onCreateView()
过程
Activity#setContentView()
-> PhoneWindow#setContentView()
-> PhoneWindow#installDecor()
-> PhoneWindow#generateLayout()
-> DecorView#onResourcesLoaded()
-> PhoneLayoutInflater#inflate()
(实际是LayoutInflater
,因为 PhoneLayoutInflater
中没有重写方法,内部多次调用重载,就不全部贴出来了) -> LayoutInflater#createViewFromTag()
(同样内部多次调用重载,就不全部贴出来了) -> LayoutInflater#tryCreateView()
LayoutInflater#tryCreateView()
方法内容如下,在 xml 中的每一个View
(fragment
标签实际也是一个View
)创建完成都会调用,进而调用 onCreateView()
方法:
public final View tryCreateView(@Nullable View parent, @NonNull String name,
@NonNull Context context,
@NonNull AttributeSet attrs)
if (name.equals(TAG_1995))
// Let's party like it's 1995!
return new BlinkLayout(context, attrs);
View view;
if (mFactory2 != null)
view = mFactory2.onCreateView(parent, name, context, attrs);
else if (mFactory != null)
view = mFactory.onCreateView(name, context, attrs);
else
view = null;
if (view == null && mPrivateFactory != null)
view = mPrivateFactory.onCreateView(parent, name, context, attrs);
return view;
setPrivateFactory
的赋值是在 Activity
的 attach()
方法中,有这样一行代码:
mWindow.getLayoutInflater().setPrivateFactory(this);
Activity
类是已经实现了 LayoutInflater.Factory2
接口的,所以直接将自身传递过来了。
其他的赋值的地方分别是 LayoutInflater#setFactory()
和 LayoutInflater#setFactory2()
方法,LayoutInflater#setFactory()
方法已过时,没有传值的地方,LayoutInflater#setFactory2()
方法的赋值开始地方有两个:AppCompatDelegateImpl#installViewFactory()
方法 和 Fragment#getLayoutInflater()
方法。
-
AppCompatDelegateImpl
为AppCompatActivity
类的委托类,AppCompatActivity
的相关操作交由其处理。 -
Fragment#getLayoutInflater()
为Fragment
的onCreateView()
提供类型为LayoutInflater
的参数。public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) if (mContentLayoutId != 0) return inflater.inflate(mContentLayoutId, container, false); return null;
就是改回调方法的第一个参数。
以上是关于Fragment状态改变与管理的主要内容,如果未能解决你的问题,请参考以下文章