本文基于 androidx fragment 1.2.2 源码分析
implementation "androidx.fragment:fragment-ktx:1.2.2"
请大家思考一个问题,我们知道 Fragment 的生命周期是与其宿主 Activity 的生命周期息息相关的,也即 Activity 的每次生命周期回调都会引发每个Fragment的类似回调,怎么实现的呢?
因此,Fragment 中两个最重要的概念出现了,FragmentManager
和 FragmentTransaction
(事务是指一组原子性的操作,这些操作是不可分割的整体,要么全完成,要么全不完成,完成后可以回滚到完成前的状态)。
FragmentManager
封装着对 Fragment 操作的各种方法,addFragment()
,removeFragment()
等等,而FragmentActivity
通过FragmentController
来操作FragmentManager
。
它们均为抽象类,需要具体的实现类。
-
FragmentManager
的实现类为FragmentManagerImpl
,其内部逻辑已全部移至 FragmentManager 中,是个空实现。 -
FragmentTransaction
的实现类为BackStackRecord
,其内部引用了 FragmentManager 的实例 ,同时重写了父类的 四个commit(...)
相关的方法。
Activity 操作 Fragment 生命周期
Activity 会在各个生命周期节点通过 FragmentController
间接调用 FragmentManager
中的各种 dispatch-
方法,进而影响 Fragment 的生命周期。
// FragmentActivity.java
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
//以下代码省略部分逻辑
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
mFragments.dispatchCreate();
}
@Override
protected void onStart() {
mFragments.dispatchStart();
}
//onResume 彻底执行完毕的回调
@Override
protected void onPostResume() {
mFragments.dispatchResume();
}
@Override
protected void onPause() {
mFragments.dispatchPause();
}
@Override
protected void onStop() {
mFragments.dispatchStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
mFragments.dispatchDestroy();
}
这里引出 Fragment 中另外两个比较重要的概念,getParentFragmentManager()
和 getChildFragmentManager()
。
注意:
requireFragmentManager()
和getFragmentManager
已弃用。
-
getChildFragmentManager()
获取的是 Fragment 中的mChildFragmentManager
; -
getParentFragmentManager()
获取的是 Fragment 中的mFragmentManager
; -
mChildFragmentManager
为 Fragment 内部的FragmentManager
// Private fragment manager for child fragments inside of this one.
@NonNull
FragmentManager mChildFragmentManager = new FragmentManagerImpl();
getParentFragmentManager()
稍显复杂
-
如果 Fragment 的直接宿主是 Activity ,则返回的是 Activity 中的
getSupportFragmentManager()
返回的FragmentManager
; -
如果 Fragment 的直接宿主是 Fragment,即该 Fragment 是一个子 Fragment,则返回的是其父 Fragment 的
getChildFragmentManager()
,
所以嵌套 Fragment 的生命周期是 父 Fragment 在各个生命周期节点上通过mChildFragmentManager
调用dispatch-
以影响其子 Fragment 的生命周期。
下面的代码均来自 androidx.fragment.app.Fragment
// The fragment manager we are associated with. Set as soon as the
// fragment is used in a transaction; cleared after it has been removed
// from all transactions.
FragmentManager mFragmentManager;
// Private fragment manager for child fragments inside of this one.
@NonNull
FragmentManager mChildFragmentManager = new FragmentManagerImpl();
// If this Fragment is contained in another Fragment, this is that container.
Fragment mParentFragment;
/**Return the FragmentManager for interacting with fragments associated with this fragment's activity. Note that this will be non-null slightly before getActivity(), during the time from when the fragment is placed in a FragmentTransaction until it is committed and attached to its activity.
If this Fragment is a child of another Fragment, the FragmentManager returned here will be the parent's getChildFragmentManager().
Deprecated
This has been removed in favor of getParentFragmentManager() which throws an IllegalStateException if the FragmentManager is null. Check if isAdded() returns false to determine if the FragmentManager is null.
See Also:
getParentFragmentManager()**/
@Nullable
@Deprecated
final public FragmentManager getFragmentManager() {
return mFragmentManager;
}
@NonNull
@Deprecated
public final FragmentManager requireFragmentManager() {
return getParentFragmentManager();
}
@NonNull
public final FragmentManager getParentFragmentManager() {
FragmentManager fragmentManager = mFragmentManager;
if (fragmentManager == null) {
throw new IllegalStateException(
"Fragment " + this + " not associated with a fragment manager.");
}
return fragmentManager;
}
@NonNull
final public FragmentManager getChildFragmentManager() {
if (mHost == null) {
throw new IllegalStateException("Fragment " + this + " has not been attached yet.");
}
return mChildFragmentManager;
}
// Returns the parent Fragment containing this Fragment. If this Fragment is attached directly to an Activity, returns null.
@Nullable
final public Fragment getParentFragment() {
return mParentFragment;
}
@NonNull
public final Fragment requireParentFragment() {
Fragment parentFragment = getParentFragment();
if (parentFragment == null) {
Context context = getContext();
if (context == null) {
throw new IllegalStateException("Fragment " + this + " is not attached to"
+ " any Fragment or host");
} else {
throw new IllegalStateException("Fragment " + this + " is not a child Fragment, it"
+ " is directly attached to " + getContext());
}
}
return parentFragment;
}
总结
在 Activity 的 Host Fragment 中替换 Fragment 利用 parentFragmentManager
,Fragment 添加子 Fragment 利用 childFragmentManager
。
# MainActivity 之 HostFragment
parentFragmentManager.commit {
addToBackStack(null)
replace<SingleStackParentFragment>(R.id.content)
}
# SingleStackParentFragment
childFragmentManager.commit {
val fragment =
SingleStackChildFragment.newInstance(
name(containerId),
1
)
replace(containerId, fragment, fragment.stableTag)
}
我们做一个总结:Activity 和 Fragment 会在各个生命周期节点通过调用子Fragment 的 parentFragmentManager
(或者说父 Fragment 的 childFragmentManager
和 Activity 的 supportFragmentManager
)中的各种 dispatch-
方法以影响寄生的 Fragment 的生命周期,同时寄生的 Fragment 也拥有自己生命周期的调用链(从状态A转移至状态B)
不得不说 Fragment 的很多 API 并不是很好用,从 androidx Fragment 的更新频率也可以看出。比如 Fragment 中的 View 和 Fragment 本身的生命周期是不一致的,存在 onDestroyView 但 Fragment 没有销毁的情况。
网友评论