从源码角度看Fragment

简介

Android系统所运行的设备中,从小屏手机到11寸平板再到超大尺寸的电视,五花八门层出不穷。一个应用如何适配这些尺寸不同的设备呢,如果只是单纯的为每个APP开发一套应用界面的话,其中的工作量将会呈指数被增长。于是乎,Fragment碎片化的概念就这样被推出了,Fragment运行在Activity中,拥有着和Activity对应的生命周期,同样能够显示与响应界面和用户的点击事件。Fragment之间是相互独立了,在Activity中,可以自由增加与删除被管理的Fragment。通过Fragment,一个APP可以做到同时适应手机、平板和电视这些尺寸不同的设备

本篇文章里,我将按惯例先放出Fragment涉及到的类图,方便大家快速熟悉主要的类与其中关系。随后我将着重讲解Activity与Fragment生命周期的调用顺序并且给出一张详细的图片用来参考,之后我会着重分析Fragment事务的实现及其原理。文章的最后我会给出简短的总结

这篇文章主要重点放在Fragment的生命周期与事务操作的流程与源码分析,具体细节、坑点与调用技巧没有做详细讨论

类图

查看大图

  • AMS控制Activity的生命周期,Activity在dispatchXXX系列方法中通过调用FragmentController来控制Fragment的生命周期
  • FragmentController是一个代理,本身没有实现重要的逻辑
  • FragmentHostCallback被FragmentController持有,引用了FragmentManager的具体实现类对象
  • FragmentManagerImpl是FragmentManager的具体实现,负责控制Fragment列表的状态,是真正做操作的一个类
  • BackStackRecord是FragmentTransaction的实现,用来实现Fragment事务的操作

Actiity与Fragment的生命周期

知道启动Activity流程的同学应该都清楚,从调用startActivity开始到应用调用onCreate为止,这期间的操作不仅仅只需要应用自身去完成,同时还需要AMS以服务端的角色参与其中,Activity的生命周期和AMS中的ActivitySupervisor所记录的状态是严格对应的,如果双方任何一端出现了异常,那么很有可能应用就会出现Crash

同理,Fragment的生命周期也是和Activity强关联一一对应的。稍微形象一点的说法,Activity就好比Fragment的服务端,Fragment的生命周期变化都是通过Activity的调用来改变的。当然,Fragment对于Activity生命周期变化的反应是不需要应用开发者自己去处理的,这些控制代码都写在了Activity生命周期的调用函数中了

有兴趣的同学可以搜索Activity的方法performXXX系列,这些方法都是默认package并且是final的,不允许被修改

以下是我自己画的一张Activity与Fragment在正常启动随后正常退出的生命周期图,与官方图不同的是,这张图明确标明了Activity与Fragment执行生命周期方法的顺序,这其中只有Activity的onCreate方法特殊,在onCreate方法内执行了Fragment的4个方法。其余的Activity方法都是在Fragment生命周期方法之前或之后执行完的

状态切换的具体方法是通过FragmentManager.moveToState来实现的,具体的实现源码最后再进行分析

查看大图

  • Activity的各个重要生命周期方法都能够在Fragment找到
  • Fragment最先与最后调用的方法分别是onAttach与onDetach方法
  • 正常打开Activity时,Activity的生命周期方法先于对应的Fragment生命周期方法被调用
  • 正常关闭Activity时,Activity的生命周期方法在对应的Fragment生命周期方法之后被调用

Fragment事务

以下是在Activity通过调用getFragmentManager获取FragmentManager对象来进行fragment管理的操作,通过调用FragmentTransation的add操作将VideoFragment的实例加入到当前Activity中

1
2
3
Fragment videoFragment = new VideoPlayerFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.add(R.id.video_fragment, videoFragment).commit();

beginTransaction与BackStackRecord

[frameworks/base/core/java/android/app/FragmentHostCallback.java]

1
2
3
FragmentManagerImpl getFragmentManagerImpl() {
return mFragmentManager;
}

通过Activity.getFragementManager层层调用,最终返回了FragmentManagerImpl实例,这之前的传递关系可以在类图中很清晰的看到

[frameworks/base/core/java/android/app/FragmentManager.java]

1
2
3
4
5
@Override
public FragmentTransaction beginTransaction() {
// 直接返回BackStackRecord的实例,这个实例实现了FragementTransaction抽象类
return new BackStackRecord(this);
}

BackStackRecord是FragmentTransaction的实现,主要维护了一个双向的链表,用以实现事务的前进与回退

[frameworks/base/core/java/android/app/BackStackRecord.java]

1
2
3
4
public FragmentTransaction add(Fragment fragment, String tag) {
doAddOp(0, fragment, tag, OP_ADD);
return this;
}

这个add操作调用的方法和其他操作其实都一样,最终会调用到addOp方法,唯一的差别在于command不同

事务操作

操作 command 意义
add OP_ADD 添加fragment
remove OP_REMOVE 删除fragment
replace OP_REPLACE 替换fragment
show OP_SHOW 显示fragment
hide OP_HIDE 隐藏fragment
attach OP_ATTACH 依附activity
detach OP_DETACH 从activity分离

commit

[frameworks/base/core/java/android/app/BackStackRecord.java]

1
2
3
4
5
6
7
8
public int commit() {
return commitInternal(false);
}
int commitInternal(boolean allowStateLoss) {
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}

调用commit方法后,BackStackRecord没有再做过多的操作,直接交给了FragmentManager进行下一步处理

[frameworks/base/core/java/android/app/FragmentManager.java]

1
2
3
4
5
6
7
8
9
10
11
public void enqueueAction(Runnable action, boolean allowStateLoss) {
synchronized (this) {
// 将commit处理操作放置到mPendingActions列表中
mPendingActions.add(action);
// 如果mPendingActions的数量唯一,则将commit执行runnable放置到主线程Looper中
if (mPendingActions.size() == 1) {
mHost.getHandler().removeCallbacks(mExecCommit);
mHost.getHandler().post(mExecCommit);
}
}
}

[frameworks/base/core/java/android/app/FragmentManager.java]

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
Runnable mExecCommit = new Runnable() {
@Override
public void run() {
execPendingActions();
}
};
public boolean execPendingActions() {
boolean didSomething = false;
// 进入死循环
while (true) {
int numActions;
synchronized (this) {
// 如果当前mPendingActions没有任务时,就会终止循环
if (mPendingActions == null || mPendingActions.size() == 0) {
break;
}
numActions = mPendingActions.size();
if (mTmpActions == null || mTmpActions.length < numActions) {
mTmpActions = new Runnable[numActions];
}
// 将mPendingActions列表的action拷贝到mTempActions数组里
mPendingActions.toArray(mTmpActions);
随后清理mPendingActions列表
mPendingActions.clear();
mHost.getHandler().removeCallbacks(mExecCommit);
}
mExecutingActions = true;
for (int i=0; i<numActions; i++) {
// 在主线程执行BackStackRecord的run方法
mTmpActions[i].run();
mTmpActions[i] = null;
}
mExecutingActions = false;
didSomething = true;
}
return didSomething;
}

FragmentManager继续commit操作之后,随后会将消息post到主线程队列中,然后挨个执行BackStackRecord的run方法

BackStackRecord.run (1)

[frameworks/base/core/java/android/app/BackStackRecord.java]

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
public void run() {
SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
// 计算出首先被remove的Fragment以及最后被add的Fragment;array维护了一个containerId与fragment对应的map
calculateFragments(firstOutFragments, lastInFragments);
// 计算完成后,会根据exit/shared element/enter这三种状态来进行切换
// 这块不具体分析了
beginTransition(firstOutFragments, lastInFragments, false);
}
private void calculateFragments(SparseArray<Fragment> firstOutFragments,
SparseArray<Fragment> lastInFragments) {
Op op = mHead;
while (op != null) {
switch (op.cmd) {
case OP_ADD:
setLastIn(lastInFragments, op.fragment);
break;
case OP_REPLACE: {
Fragment f = op.fragment;
if (mManager.mAdded != null) {
for (int i = 0; i < mManager.mAdded.size(); i++) {
Fragment old = mManager.mAdded.get(i);
if (f == null || old.mContainerId == f.mContainerId) {
if (old == f) {
f = null;
} else {
setFirstOut(firstOutFragments, old);
}
}
}
}
setLastIn(lastInFragments, f);
break;
}
case OP_REMOVE:
setFirstOut(firstOutFragments, op.fragment);
break;
case OP_HIDE:
setFirstOut(firstOutFragments, op.fragment);
break;
case OP_SHOW:
setLastIn(lastInFragments, op.fragment);
break;
case OP_DETACH:
setFirstOut(firstOutFragments, op.fragment);
break;
case OP_ATTACH:
setLastIn(lastInFragments, op.fragment);
break;
}
op = op.next;
}
}

commit的第一步操作很简单,遍历所有的Op对象,根据cmd规则计算出firstOutFragment与lastInFragment,containerId不同的话会产生多条数据;以下是上面代码的具体规则

cmd firstOutFragments lastInFragements
OP_ADD - 被添加的fragment
OP_REPLACE 被替换的fragment 新的fragment
OP_REMOVE 被删除的fragment -
OP_HIDE 被隐藏的fragment -
OP_SHOW - 被显示的fragment
OP_DETACH 被detach的fragment -
OP_ATTACH - 被attach的fragment

BackStackRecord.run (2)

我们可以先看看Op类的具体实现,很明显的可以看出这是一个支持前进与回退的双向链表

[frameworks/base/core/java/android/app/BackStackRecord.java]

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
final class BackStackRecord extends FragmentTransaction implements
FragmentManager.BackStackEntry, Runnable {
static final class Op {
// 双向的链表,维护着next和prev两个引用
Op next;
Op prev;
// 具体命令
int cmd;
// 被操作的fragment
Fragment fragment;
// 进入退出的动画
int enterAnim;
int exitAnim;
// 弹出弹入的动画
int popEnterAnim;
int popExitAnim;
ArrayList<Fragment> removed;
}
// 引用着头与尾
Op mHead;
Op mTail;
int mNumOp;
int mEnterAnim;
int mExitAnim;
int mPopEnterAnim;
int mPopExitAnim;

[frameworks/base/core/java/android/app/BackStackRecord.java]

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
public void run() {
Op op = mHead;
// 遍历Op双向链表
while (op != null) {
switch (op.cmd) {
case OP_ADD: {
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 = 0; i < mManager.mAdded.size(); i++) {
// 寻找需要被替换的fragment
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;
// 找到后进行移除
mManager.removeFragment(old, mTransition, mTransitionStyle);
}
}
}
}
// 将新的fragment进行add
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;
}
// 调用moveToState进行Fragment状态与生命周期的切换
mManager.moveToState(mManager.mCurState, mTransition,
mTransitionStyle, true);
if (mAddToBackStack) {
mManager.addBackStackState(this);
}
}

这段代码具体的思路是根据cmd的不同,调用FragmentManager的不同方法:

cmd 调用FragmentManager方法
OP_ADD addFragment
OP_REPLACE removeFragment->addFragment
OP_REMOVE removeFragment
OP_HIDE hideFragment
OP_SHOW showFragment
OP_DETACH detachFragment
OP_ATTACH attachFragment

Fragmentmanager执行Op具体操作

[frameworks/base/core/java/android/app/FragmentManager.java]

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 addFragment(Fragment fragment, boolean moveToStateNow) {
// 设置fragment active标志为true
makeActive(fragment);
if (!fragment.mDetached) {
if (mAdded.contains(fragment)) {
throw new IllegalStateException("Fragment already added: " + fragment);
}
// 添加至mAdded列表中
mAdded.add(fragment);
fragment.mAdded = true;
fragment.mRemoving = false;
if (fragment.mHasMenu && fragment.mMenuVisible) {
mNeedMenuInvalidate = true;
}
}
}
public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
final boolean inactive = !fragment.isInBackStack();
if (!fragment.mDetached || inactive) {
// 从mAdded列表中删除fragment
if (mAdded != null) {
mAdded.remove(fragment);
}
if (fragment.mHasMenu && fragment.mMenuVisible) {
mNeedMenuInvalidate = true;
}
fragment.mAdded = false;
fragment.mRemoving = true;
// 移出后通过判断inactive这个flag来判断fragment之后的状态
moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
transition, transitionStyle, false);
}
}
public void showFragment(Fragment fragment, int transition, int transitionStyle) {
if (fragment.mHidden) {
fragment.mHidden = false;
if (fragment.mView != null) {
// 将fragment的mView设置为显示状态即可
fragment.mView.setVisibility(View.VISIBLE);
}
// 回调隐藏方法
fragment.onHiddenChanged(false);
}
}
public void hideFragment(Fragment fragment, int transition, int transitionStyle) {
if (!fragment.mHidden) {
fragment.mHidden = true;
if (fragment.mView != null) {
// 将fragment的view置为GONE
fragment.mView.setVisibility(View.GONE);
}
// 回调fragment显示方法
fragment.onHiddenChanged(true);
}
}
public void attachFragment(Fragment fragment, int transition, int transitionStyle) {
if (fragment.mDetached) {
fragment.mDetached = false;
if (!fragment.mAdded) {
if (mAdded == null) {
mAdded = new ArrayList<Fragment>();
}
// 将fragment加入到mAdded列表中
mAdded.add(fragment);
fragment.mAdded = true;
if (fragment.mHasMenu && fragment.mMenuVisible) {
mNeedMenuInvalidate = true;
}
// 更新fragment的状态
moveToState(fragment, mCurState, transition, transitionStyle, false);
}
}
}
public void detachFragment(Fragment fragment, int transition, int transitionStyle) {
if (!fragment.mDetached) {
fragment.mDetached = true;
if (fragment.mAdded) {
if (mAdded != null) {
// 移出fragment
mAdded.remove(fragment);
}
if (fragment.mHasMenu && fragment.mMenuVisible) {
mNeedMenuInvalidate = true;
}
fragment.mAdded = false;
// 将fragment状态置为CREATED
moveToState(fragment, Fragment.CREATED, transition, transitionStyle, false);
}
}
}
  • add与remove方法对应,核心操作在于处理mAdded列表
  • show与hide方法对应,核心操作在于显示或隐藏Fragment自身携带的view
  • attach与detach方法对应,核心操作在于处理mAdded列表并更新当前fragment的状态

Fragment状态

FragmentManager与Fragment都使用到了状态模式来实现。FragmentManager有个mCurState字段,用来表示当前Activity中的Fragment总体状态,是通过调用Activity.dispatchXXX系列方法来变化的。Fragment的状态一共有5种,和FragmentManager的状态是对应的,用来指明当前Fragment所处于的状态,以方便与Activity同步生命周期

状态表格

状态 意义 入口方法
0 INITIALIZING Fragment尚未初始化或者已经被销毁 dispatchDestroy
1 CREATED Fragment已被创建 dispatchDestoryView
2 ACTIVITY_CREATED Fragemtn所在Activity已经创建成功 dispatchActivityCreated
3 STOPPED Fragment已经被创建,但是尚未不可见 dispatchStop
4 STARTED Fragment已经可见,但是还不可以接收点击事件 dispatchPause
5 RESUMED Fragment已经可见并且可以接收点击事件 dispatchResume

状态变化: moveToState

[frameworks/base/core/java/android/app/FragmentManager.java]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 被Activity在各个生命周期通过FragmentManager调用的方法,用来切换Fragment状态、更换Fragment生命周期
void moveToState(int newState, boolean always) {
moveToState(newState, 0, 0, always);
}
void moveToState(int newState, int transit, int transitStyle, boolean always) {
// 更新FragmentManager状态
mCurState = newState;
if (mActive != null) {
boolean loadersRunning = false;
for (int i=0; i<mActive.size(); i++) {
// 依次更新被活跃Fragment的状态
Fragment f = mActive.get(i);
if (f != null) {
moveToState(f, newState, transit, transitStyle, false);
if (f.mLoaderManager != null) {
loadersRunning |= f.mLoaderManager.hasRunningLoaders();
}
}
}
}
}

以上的两个方法依次被Activity间接调用到,直至调用到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
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
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
// Fragment尚未被加入的话会一直停留在CREATED状态
if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
newState = Fragment.CREATED;
}
// 正在做移除操作的话,状态不会改变
if (f.mRemoving && newState > f.mState) {
newState = f.mState;
}
// 延迟start的话不允许fragment的状态在STARTED及其之后
if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) {
newState = Fragment.STOPPED;
}
// 如果新状态大于当前状态,即onCreate->onResume的正向操作
if (f.mState < newState) {
if (f.mFromLayout && !f.mInLayout) {
return;
}
// 进入状态切换
switch (f.mState) {
// 当前fragment尚未被创建或者已经被destroy
case Fragment.INITIALIZING:
// 调用Fragment.onAttach方法
f.onAttach(mHost.getContext());
// 调用FragmentonCreate方法
if (!f.mRetaining) {
f.performCreate(f.mSavedFragmentState);
}
f.mRetaining = false;
if (f.mFromLayout) {
// 调用Fragment.onCreateView方法
f.mView = f.performCreateView(f.getLayoutInflater(
f.mSavedFragmentState), null, f.mSavedFragmentState);
if (f.mView != null) {
// 调用Fragment.onViewCreated方法
f.onViewCreated(f.mView, f.mSavedFragmentState);
}
}
// 当前fragment状态为已经被创建
case Fragment.CREATED:
if (newState > Fragment.CREATED) {
if (!f.mFromLayout) {
if (f.mView != null) {
// 调用Fragment.onViewCreated方法
f.onViewCreated(f.mView, f.mSavedFragmentState);
}
}
// 调用Fragment.onActivityCreated方法
f.performActivityCreated(f.mSavedFragmentState);
}
case Fragment.ACTIVITY_CREATED:
case Fragment.STOPPED:
if (newState > Fragment.STOPPED) {
// Fragment.onStart方法
f.performStart();
}
case Fragment.STARTED:
if (newState > Fragment.STARTED) {
f.mResumed = true;
// 调用Fragment.onResume方法
f.performResume();
// Get rid of this in case we saved it and never needed it.
f.mSavedFragmentState = null;
f.mSavedViewState = null;
}
}
// 当前状态处于倒退的状态,即走onPause->onDestroy这个流程
} else if (f.mState > newState) {
switch (f.mState) {
case Fragment.RESUMED:
if (newState < Fragment.RESUMED) {
// 调用Fragment.onPause方法
f.performPause();
f.mResumed = false;
}
case Fragment.STARTED:
if (newState < Fragment.STARTED) {
// 调用Fragment.onStop方法
f.performStop();
}
case Fragment.STOPPED:
case Fragment.ACTIVITY_CREATED:
if (newState < Fragment.ACTIVITY_CREATED) {
// 调用Fragment.onDestroyView方法
}
case Fragment.CREATED:
if (newState < Fragment.CREATED) {
if (f.mAnimatingAway != null) {
f.mStateAfterAnimating = newState;
newState = Fragment.CREATED;
} else {
if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
if (!f.mRetaining) {
// 调用Fragment.onDestroy方法
f.performDestroy();
}
f.mCalled = false;
// // 调用Fragment.onDetach方法
f.onDetach();
if (!keepActive) {
if (!f.mRetaining) {
// 标记Fragment为inactive
makeInactive(f);
} else {
f.mHost = null;
f.mParentFragment = null;
f.mFragmentManager = null;
f.mChildFragmentManager = null;
}
}
}
}
}
}
// 更新Fragment的状态
f.mState = newState;
}

Fragment状态的切换分为两类

  • 第一类是正向的切换顺序,INITIALIZEING->CREATED->ACTIVITY_CREATED->STARTED->RESUMED,值变得越来越大,代表着Fragment从初始化到可见可交互的状态
  • 第二类是反向的切换顺序,RESUMED->STARTED->STOPPED->CREATED->INITALIZING,值变得越来越小,代表着Fragment从可见可交互到与Activity分离的状态

总结

  • Activity与Fragment的生命周期一一对应,乍眼一看Fragment很像一个组件。但是它并不是,实际上所有的操作都是被Activity驱动完成的,期间的所有操作也不涉及与system_server进程交互的跨进程操作
  • Fragment的显示与隐藏实际上就是维护了一个View的实例,界面的切换是使用Animator来控制并实现的
  • Fragment的事务的实现是一个双向的链表,所以能支持事务的回退与前进
扫码支持0.99元,您的支持将鼓励我继续创作!