0%

Fragment源码分析

概述

Fragment表示 Activity 中的行为或用户界面部分。您可以将多个 Fragment 组合在一个 Activity 中来构建多窗格 UI,以及在多个 Activity 中重复使用某个 Fragment。您可以将 Fragment 视为 Activity 的模块化组成部分,它具有自己的生命周期,能接收自己的输入事件,并且您可以在 Activity 运行时添加或移除 Fragment。
Fragment 必须始终嵌入在 Activity 中,其生命周期直接受宿主 Activity 生命周期的影响。 例如,当 Activity 暂停时,其中的所有 Fragment 也会暂停;当 Activity 被销毁时,所有 Fragment 也会被销毁。 不过,当 Activity 正在运行(处于已恢复生命周期状态)时,您可以独立操纵每个 Fragment,如添加或移除它们。 当您执行此类 Fragment 事务时,您也可以将其添加到由 Activity 管理的返回栈 — Activity 中的每个返回栈条目都是一条已发生 Fragment 事务的记录。 返回栈让用户可以通过按返回按钮撤消 Fragment 事务(后退)。

当您将 Fragment 作为 Activity 布局的一部分添加时,它存在于 Activity 视图层次结构的某个 ViewGroup 内部,并且 Fragment 会定义其自己的视图布局。您可以通过在 Activity 的布局文件中声明Fragment,将其作为 <fragment> 元素插入您的 Activity 布局中,或者通过将其添加到某个现有 ViewGroup,利用应用代码进行插入。不过,Fragment 并非必须成为 Activity 布局的一部分;您还可以将没有自己 UI 的 Fragment 用作 Activity 的不可见工作线程。

本文将通过分析源码,对 Fragment 的创建、销毁以及生命周期做一个更深入的认识。

建议读者在看这篇文章的时候,先看下Fragment事务管理源码分析,对Fragment管理类先有一个比较清楚的认识。

分析入口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 构造并显示Fragment
*
* @param containerViewId 容器控件id
* @param clz Fragment类
*/
protected void showFragment(@IdRes int containerViewId, Class<? extends Fragment> clz) {
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();//开始事务管理
try {
Fragment f = clz.newInstance();
ft.add(containerViewId, f, clz.getName());//添加操作
ft.commit();//提交事务
} catch (Exception e) {
e.printStackTrace();
}
}

上面的代码就是动态地往containerViewId里添加一个Fragment并让它显示出来,可以看到,这个涉及到Fragment的事务管理,详细可以参考Fragment事务管理源码分析,这里就不再阐述了。

代码分析

BackStackRecord#run

调用了commit之后,真正执行的地方是在BackStackRecord的run方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
public void run() {

......

if (mManager.mCurState >= Fragment.CREATED) {
SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
calculateFragments(firstOutFragments, lastInFragments);
beginTransition(firstOutFragments, lastInFragments, false);
}
//遍历链表,根据cmd事务类型依次处理事务
Op op = mHead;
while (op != null) {
switch (op.cmd) {
case OP_ADD: {
//添加一个新的Fragment
Fragment f = op.fragment;
f.mNextAnim = op.enterAnim;
mManager.addFragment(f, false);
}
break;
case OP_REPLACE: {
Fragment f = op.fragment;
int containerId = f.mContainerId;
if (mManager.mAdded != null) {
for (int i = mManager.mAdded.size() - 1; i >= 0; i--) {
Fragment old = mManager.mAdded.get(i);
if (old.mContainerId == containerId) {
if (old == f) {
op.fragment = f = null;
} else {
if (op.removed == null) {
op.removed = new ArrayList<Fragment>();
}
op.removed.add(old);
old.mNextAnim = op.exitAnim;
if (mAddToBackStack) {
old.mBackStackNesting += 1;
}
mManager.removeFragment(old, mTransition, mTransitionStyle);
}
}
}
}
if (f != null) {
f.mNextAnim = op.enterAnim;
mManager.addFragment(f, false);
}
}
break;
case OP_REMOVE: {
Fragment f = op.fragment;
f.mNextAnim = op.exitAnim;
mManager.removeFragment(f, mTransition, mTransitionStyle);
}
break;
case OP_HIDE: {
Fragment f = op.fragment;
f.mNextAnim = op.exitAnim;
mManager.hideFragment(f, mTransition, mTransitionStyle);
}
break;
case OP_SHOW: {
Fragment f = op.fragment;
f.mNextAnim = op.enterAnim;
mManager.showFragment(f, mTransition, mTransitionStyle);
}
break;
case OP_DETACH: {
Fragment f = op.fragment;
f.mNextAnim = op.exitAnim;
mManager.detachFragment(f, mTransition, mTransitionStyle);
}
break;
case OP_ATTACH: {
Fragment f = op.fragment;
f.mNextAnim = op.enterAnim;
mManager.attachFragment(f, mTransition, mTransitionStyle);
}
break;
default: {
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
}
}

op = op.next;
}

mManager.moveToState(mManager.mCurState, mTransition,
mTransitionStyle, true);

if (mAddToBackStack) {
mManager.addBackStackState(this);
}
}

因为我们调用的是add操作,所以执行的代码片段是:

1
2
3
4
5
6
case OP_ADD: {
Fragment f = op.fragment;
f.mNextAnim = op.enterAnim;
mManager.addFragment(f, false);
}
break;

参数解释:

  • op.fragment:showFragment中创建的Fragment实例,并且现在Fragment的mTag、mFragmentId、mContainerId已被初始化过了
  • op.enterAnim:入场动画,可以先不管
  • mManager:FragmentManagerImpl实例

FragmentManagerImpl#addFragment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public void addFragment(Fragment fragment, boolean moveToStateNow) {
//已添加的Fragment列表
if (mAdded == null) {
mAdded = new ArrayList<Fragment>();
}

//设置Fragment的mIndex,并把Fragment添加到mActive列表
makeActive(fragment);

//判断是否被detach。默认为false
if (!fragment.mDetached) {
if (mAdded.contains(fragment)) {
throw new IllegalStateException("Fragment already added: " + fragment);
}
//把Fragment添加到mAdded列表
mAdded.add(fragment);
//设置Fragment标记位
fragment.mAdded = true;
fragment.mRemoving = false;
//判断是否需要刷新菜单
if (fragment.mHasMenu && fragment.mMenuVisible) {
mNeedMenuInvalidate = true;
}
//在这次分析中moveToStateNow为false,moveToState方法在本方法外层方法中调用
if (moveToStateNow) {
moveToState(fragment);
}
}
}

addFragment里面把Fragment加入mActive和mAdded列表,并且设置标记为fragment.mAdded为true,fragment.mRemoving为false。
执行完ADD操作后,执行moveToState,moveToState顾名思义,就是把Fragment变为某种状态

1
2
3
4
5
6
7
8
//mManager.mCurState的状态很重要,我们下面会分析它现在处于什么状态
mManager.moveToState(mManager.mCurState, mTransition,
mTransitionStyle, true);

//添加本次操作到回退栈中
if (mAddToBackStack) {
mManager.addBackStackState(this);
}

Fragment状态

我们知道Fragment的生命周期是依赖于Activity的,比如Activity处于onResume,那么Fragment也会处于onResume状态,这里的参数mManager.mCurState对应的状态有:

1
2
3
4
5
6
7
static final int INVALID_STATE = -1;   // Invalid state used as a null value.
static final int INITIALIZING = 0; // Not yet created.
static final int CREATED = 1; // Created.
static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.
static final int STOPPED = 3; // Fully created, not started.
static final int STARTED = 4; // Created and started, not resumed.
static final int RESUMED = 5; // Created started and resumed.

mCurState的初始状态是Fragment.INITIALIZING,那么在BackStackRecord中调用moveToState的时候,mCurState是什么值呢?它是会受Activity生命周期影响而变化的,我们来看下FragmentActivity的代码

1
2
3
4
5
6
7
8
9
10
11
12
@SuppressWarnings("deprecation")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
//绑定FragmentManager
mFragments.attachHost(null /*parent*/);

super.onCreate(savedInstanceState);
... ...

//分发Fragment的create事件
mFragments.dispatchCreate();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public void dispatchCreate() {
mHost.mFragmentManager.dispatchCreate();
}

public void dispatchCreate() {
mStateSaved = false;
//注意这里设置了新的state
moveToState(Fragment.CREATED, false);
}

void moveToState(int newState, boolean always) {
moveToState(newState, 0, 0, always);
}

void moveToState(int newState, int transit, int transitStyle, boolean always) {

... ...
//给mCurState赋值
mCurState = newState;
... ...
}

在onCreate中把mCurState变为Fragment.CREATED状态了,Activity的其他生命周期方法回调的时候,也会改变这个状态,大致整理如下:

  • onCreate:Fragment.CREATED
  • onStart:Fragment.ACTIVITY_CREATED–>Fragment.STARTED (Fragment.ACTIVITY_CREATED只会在Activity创建之后触发一次,Fragment.STARTED每次onStart的时候都会触发)
  • onResume:Fragment.RESUMED
  • onPause:Fragment.STARTED
  • onStop:Fragment.STOPPED
  • onDestroy:Fragment.INITIALIZING

下面是一张状态迁移图:
2019-9-2-11-22-55.png

所以随着Activity生命周期的推进,Activity内所有Fragment的生命周期也会跟着推进。从Activity创建到显示出来,最后会处于onResume状态,那么我们这次就直接分析当前Activity处于onResume调用之后的情形好了。所以假定现在mCurState为Fragment.RESUMED

让我们继续跟踪FragmentManagerImpl

FragmentManagerImpl#moveToState

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
void moveToState(int newState, int transit, int transitStyle, boolean always) {
if (mHost == null && newState != Fragment.INITIALIZING) {
throw new IllegalStateException("No activity");
}

if (!always && mCurState == newState) {
return;
}

mCurState = newState;
if (mActive != null) {
boolean loadersRunning = false;
//遍历所有Active状态的Fragment,改变所有Fragment的状态
for (int i=0; i<mActive.size(); i++) {
Fragment f = mActive.get(i);
if (f != null) {
//关键代码
moveToState(f, newState, transit, transitStyle, false);
if (f.mLoaderManager != null) {
loadersRunning |= f.mLoaderManager.hasRunningLoaders();
}
}
}

if (!loadersRunning) {
startPendingDeferredFragments();
}

//让Activity刷新Menu
if (mNeedMenuInvalidate && mHost != null && mCurState == Fragment.RESUMED) {
mHost.onInvalidateOptionsMenu();
mNeedMenuInvalidate = false;
}
}
}

设置最新的mCurState状态,通过上面的分析,我们知道newState等于Fragment.RESUMED。遍历mActive列表中保存的Fragment,改变Fragment状态,这里又调用了一个moveToState方法,这个方法就是真正回调Fragment生命周期的地方

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {

// Fragments被detach或Fragment没有添加到mAdded列表的话,设置目标Fragment的新状态为CREATED状态,此次分析中不会进入这个分支
if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
newState = Fragment.CREATED;
}
//此次分析中f.mRemoving为false
if (f.mRemoving && newState > f.mState) {
// While removing a fragment, we can't change it to a higher state.
newState = f.mState;
}
// 是否延时启动
if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) {
newState = Fragment.STOPPED;
}

if (f.mState < newState) {
//此次命中的分支
......

//根据Fragment当前的状态,选择case的分支。需要注意的是,这里的switch case是没有break语句的。这种设计可以让Fragment把自身的状态依次推进到目标状态
switch (f.mState) {
case Fragment.INITIALIZING:
if (f.mSavedFragmentState != null) {
......
}
f.mHost = mHost;
//mParent是在FragmentActivity的onCreate方法中调用attachHost传进来的,传进来的是空值
f.mParentFragment = mParent;
f.mFragmentManager = mParent != null
? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
f.mCalled = false;
//【Fragment生命周期】onAttach回调,里面会把mCalled设置为true
f.onAttach(mHost.getContext());
if (!f.mCalled) {
throw new SuperNotCalledException("Fragment " + f
+ " did not call through to super.onAttach()");
}

if (f.mParentFragment == null) {
//让Activity可以监听到Fragment的attach
mHost.onAttachFragment(f);
} else {
f.mParentFragment.onAttachFragment(f);
}

//f.mRetaining默认为false
if (!f.mRetaining) {
//关键代码,内部会调用【Fragment生命周期】onCreate
f.performCreate(f.mSavedFragmentState);
} else {
f.restoreChildFragmentState(f.mSavedFragmentState, true);
f.mState = Fragment.CREATED;
}
f.mRetaining = false;

//Fragment是否定义在Layout文件的<fragment>标签中的,本次栗子为代码动态添加Fragment,所以为false
if (f.mFromLayout) {
// For fragments that are part of the content view
// layout, we need to instantiate the view immediately
// and the inflater will take care of adding it.
f.mView = f.performCreateView(f.getLayoutInflater(
f.mSavedFragmentState), null, f.mSavedFragmentState);
if (f.mView != null) {
f.mView.setSaveFromParentEnabled(false);
if (f.mHidden) f.mView.setVisibility(View.GONE);
f.onViewCreated(f.mView, f.mSavedFragmentState);
}
}
//注意,这里没有break
case Fragment.CREATED:
if (newState > Fragment.CREATED) {
if (!f.mFromLayout) {
//开始创建Fragment的view
ViewGroup container = null;
if (f.mContainerId != 0) {
if (f.mContainerId == View.NO_ID) {
throwException(new IllegalArgumentException(""));
}

//调用Activity的findViewById方法查找控件
container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
if (container == null && !f.mRestored) {
......
}
}
f.mContainer = container;
//关键代码,内部会调用【Fragment生命周期】onCreateView,并返回Fragment中new出的视图
f.mView = f.performCreateView(f.getLayoutInflater(
f.mSavedFragmentState), container, f.mSavedFragmentState);
if (f.mView != null) {
f.mView.setSaveFromParentEnabled(false);
if (container != null) {
//设置入场动画
Animator anim = loadAnimator(f, transit, true,
transitionStyle);
if (anim != null) {
anim.setTarget(f.mView);
setHWLayerAnimListenerIfAlpha(f.mView, anim);
anim.start();
}
//把Fragment的view加入到父控件
container.addView(f.mView);
}
if (f.mHidden) f.mView.setVisibility(View.GONE);

//【Fragment生命周期】onViewCreated回调
f.onViewCreated(f.mView, f.mSavedFragmentState);
}
}

//关键代码,内部会调用【Fragment生命周期】onActivityCreated
f.performActivityCreated(f.mSavedFragmentState);
if (f.mView != null) {
f.restoreViewState(f.mSavedFragmentState);
}
f.mSavedFragmentState = null;
}
case Fragment.ACTIVITY_CREATED:
if (newState > Fragment.ACTIVITY_CREATED) {
f.mState = Fragment.STOPPED;
}
case Fragment.STOPPED:
if (newState > Fragment.STOPPED) {
if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
//关键代码,内部会调用【Fragment生命周期】onStart
f.performStart();
}
case Fragment.STARTED:
if (newState > Fragment.STARTED) {
//关键代码,内部会调用【Fragment生命周期】onResume
f.performResume();
// Get rid of this in case we saved it and never needed it.
f.mSavedFragmentState = null;
f.mSavedViewState = null;
}
}
} else if (f.mState > newState) {
//state降级处理
......
}

if (f.mState != newState) {
f.mState = newState;
}
}

这段代码逻辑还是比较长,我把注释写在代码里了。可以看到,这个代码写得很巧妙,通过switch case控制,可以一层一层地把Fragment的生命周期推进下去,比如当前fragnemt的state是Fragment.STARTED,那么它就只会执行performResume,如果Fragment的状态是Fragment.INITIALIZING,那么就会从switch的最开始依次执行下来,把Fragment的生命周期onAttach–>onResume依次调用。
简要说明下上面的代码:

  • mHost是FragmentHostCallback抽象类的实例,它的实现类是Activity的HostCallbacks
  • mParent为null
  • mHost.getContext()获取的context就是宿主Activity实例
  • Fragment中创建的View会自动通过container.addView(f.mView)添加到父控件中

很多Fragment的生命周期是通过Fragment的performXxx()方法去调用的,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void performCreate(Bundle savedInstanceState) {
......
onCreate(savedInstanceState);
......
}

View performCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
......
return onCreateView(inflater, container, savedInstanceState);
}

void performActivityCreated(Bundle savedInstanceState) {
......
onActivityCreated(savedInstanceState);
......
}

void performStart() {
......
onStart();
......
}

void performResume() {
......
onResume();
......
}

Fragment状态的降级操作

有些童鞋们可能会有疑问,上面只分析到了onAttach->onResume生命周期的回调,那onPause、onDestroy等方法又是什么时候执行的呢?我们再看下刚才的代码

1
2
3
4
5
6
if (f.mState < newState) {
......
} else if (f.mState > newState) {
//state降级处理
......
}

答案就是在else if分支里面,比如当Acivity锁屏的时候,就Activity生命周期会自动回调onPause,从而触发dispatchPause,在里面调用moveToState(Fragment.STARTED, false);
由于Fragment当前的状态是RESUMED状态,大于newState,所以就会走else if的分支,触发相应的生命周期方法。else if分支的逻辑和state升级的差不多,这里就再进行分析了

生命周期

2019-9-2-11-26-16.png
最后,放张官网上公布的Fragment生命周期图,通过代码分析,我们发现代码的中生命周期的调用顺序和图中确实是一致的

总结

本文大致地从源码的角度分析了Fragment创建、生命周期回调的过程,如果读者对Fragment的removereplacehidedetachattach等操作有兴趣的话,可以自行分析,核心代码主要在BackStackRecord类的run方法以及FragmentManagerImpl的moveToState方法中。

chenhang wechat