This page looks best with JavaScript enabled

理解 Fragment

 ·  ☕ 8 min read

理解 Fragment 的实现原理, FragmentTransaction 的事务机制等.

Fragment 的添加过程

使用如下代码:

1
2
3
4
5
6
7
setOnClickListener {
    with(supportFragmentManager) {
        beginTransaction()
            .add(R.id.fragment_container, MFragment.newInstance())
            .commit()
    }
}

方法调用栈:

Fragment Commit Flow

通过看调用栈中绿色的分布也能大致看出, 整个过程分了两个步骤.

对 Fragment 的操作需要先在 Activity 获取 FragmentManager, 那 FragmentManager 是从哪里拿到的呢?

FragmentManager 的创建

android.app.Activity 这个祖先类中的 getFragmentManager 方法已经 deprecated, 推荐我们用 android.support.v4.app.FragmentActivity#getSupportFragmentManager, 所以我们自己的 Activity 一般都继承了那些继承自 FragmentActivity 的 Activity(比如: AppCompatActivity).

FragmentActivity

androidx.fragment.app.FragmentActivity

FragmentActivity 的 getSupportFragmentManager:

1
2
3
4
public FragmentManager getSupportFragmentManager() {
    // 调用 mFragments 的方法
    return mFragments.getSupportFragmentManager();
}

mFragments 是 FragmentActivity 在内部构造的一个 FragmentController 类型的变量:

1
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());

FragmentController

androidx.fragment.app.FragmentController

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public static FragmentController createController(FragmentHostCallback<?> callbacks) {
    return new FragmentController(callbacks);
}

private FragmentController(FragmentHostCallback<?> callbacks) {
    mHost = callbacks;
}

// FragmentController 的 getSupportFragmentManager 方法是调用的其构造时传入的 callbacks
FragmentManager getSupportFragmentManager() {
    return mHost.mFragmentManager;
}

查看 FragmentController 内部的其他方法, 最后都是代理给 mHost 执行了. mHost 就是 FragmentActivity 在创建 FragmentController 时传入的 HostCallbacks.

HostCallbacks 是 FragmentActivity 的一个内部类, 其继承了 FragmentHostCallback:

HostCallbacks

androidx.fragment.app.FragmentActivity.HostCallbacks

1
2
3
4
5
class HostCallbacks extends FragmentHostCallback<FragmentActivity> implements ViewModelStoreOwner, OnBackPressedDispatcherOwner {
    public HostCallbacks() {
        super(FragmentActivity.this /*fragmentActivity*/);
    }
}

androidx.fragment.app.FragmentHostCallback

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
public abstract class FragmentHostCallback<E> extends FragmentContainer {
    private final Activity mActivity;
    private final Context mContext;
    private final Handler mHandler;
    private final int mWindowAnimations;

    // 创建 FragmentManager, 使用的是 FragmentManagerImpl
    final FragmentManager mFragmentManager = new FragmentManagerImpl();

    // HostCallbacks 中调用的是这个构造函数
    FragmentHostCallback(FragmentActivity activity) {
        this(activity, activity /*context*/, new Handler(), 0 /*windowAnimations*/);
    }

    FragmentHostCallback(Activity activity,Context context, Handler handler, int windowAnimations) {
        mActivity = activity;
        mContext = context;
        mHandler = handler;
        mWindowAnimations = windowAnimations;
    }
}

FragmentManagerImpl

androidx.fragment.app.FragmentManagerImpl

FragmentManagerImpl 继承了 FragmentManager, 自己没有特别的实现

1
2
class FragmentManagerImpl extends FragmentManager {
}

一图胜千言

概括图

至此, FragmentManager 的创建过程梳理结束, FragmentActivity 在创建时会创建一个 HostCallbacks 和 FragmentController, HostCallbacks 会在创建时创建 FragmentManager. FragmentController 会持有 HostCallbacks 对象的引用, 调用 FragmentController 的方法内部都将调用 HostCallbacks 对应的方法.


放大上面大图左侧的部分, 可以看addcommit 两个操作的调用栈:

add && commit

add 过程

整体调用栈:

FragmentManager: beginTransaction
    BackStackRecord: add -> doAddOp
        FragmentTransaction: doAddOp -> addOp

首先, FragmentManger 的 beginTransaction 方法返回了一个 BackStackRecord 对象

1
2
3
public FragmentTransaction beginTransaction() {
    return new BackStackRecord(this);
}

BackStackRecord

androidx.fragment.app.BackStackRecord

BackStackRecord 类继承自 FragmentTransaction, FragmentTransaction 是一个抽象类

1
2
3
4
// 构造函数
public BackStackRecord(FragmentManagerImpl manager) {
    mManager = manager;
}

比如调用 add(R.id.fragment_container, MFragment.newInstance())

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// BackStackRecord 中没有实现该方法, 所以会调用父类 FragmentTransaction 的 add
public FragmentTransaction add(@IdRes int containerViewId, @NonNull Fragment fragment) {
    doAddOp(containerViewId, fragment, null, OP_ADD);
    return this;
}

// OP_ADD 是在 FragmentTransaction 中定义的一个常量, 看样子后面会用到**命令模式**.
// 其他类似常量
int OP_NULL = 0;
int OP_ADD = 1;
int OP_REPLACE = 2;
int OP_REMOVE = 3;
int OP_HIDE = 4;
int OP_SHOW = 5;
int OP_DETACH = 6;
int OP_ATTACH = 7;
int OP_SET_PRIMARY_NAV = 8;
int OP_UNSET_PRIMARY_NAV = 9;
int OP_SET_MAX_LIFECYCLE = 10;

接着 doAddOp:

1
2
3
4
5
6
7
// BackStackRecord 复写了 doAddOp, 所以会调用 BackStackRecord 自己实现的 doAddOp
void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
    // 调用父类的 doAddOp
    super.doAddOp(containerViewId, fragment, tag, opcmd);
    // 可见 Fragment 的 FragmentManager 是在这一步赋值的
    fragment.mFragmentManager = mManager;
}
 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
// FragmentTransaction 的 doAddOp
void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
    final Class<?> fragmentClass = fragment.getClass();
    final int modifiers = fragmentClass.getModifiers();
    // 如果 fragment: 是匿名类 || 不是 public || 是内部类但不是静态的, 则抛出异常
    if (fragmentClass.isAnonymousClass() || !Modifier.isPublic(modifiers)
            || (fragmentClass.isMemberClass() && !Modifier.isStatic(modifiers))) {
        throw new IllegalStateException("Fragment " + fragmentClass.getCanonicalName() + "...");
    }

    if (tag != null) {
        // fragment 的 tag 指定之后不能修改
        if (fragment.mTag != null && !tag.equals(fragment.mTag)) {
            throw new IllegalStateException("Can't change tag of fragment");
        }
        fragment.mTag = tag;
    }

    if (containerViewId != 0) {
        if (containerViewId == View.NO_ID) {
            throw new IllegalArgumentException("Can't add fragment to container view with no id");
        }
        if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
            throw new IllegalStateException("Can't change container ID of fragment ...");
        }
        fragment.mContainerId = fragment.mFragmentId = containerViewId;
    }

    // 构造一个 Op, 然后调用 addOp
    addOp(new Op(opcmd, fragment));
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// FragmentTransaction addOp
void addOp(Op op) {
    // 将 op 添加到 mOps 中
    // mOps: 类型为 ArrayList<Op>, FragmentTransaction 的一个成员变量
    mOps.add(op);
    op.mEnterAnim = mEnterAnim;
    op.mExitAnim = mExitAnim;
    op.mPopEnterAnim = mPopEnterAnim;
    op.mPopExitAnim = mPopExitAnim;
}

一图胜千言

BackStackRecord ops

至此, add 调用过程结束, 会在 BackStackRecord 的 mOps 数组中添加一条 Op 记录, Op 记录着这次操作的命令(mCmd)和操作的 Fragment(mFragnment).

commit 过程

整体调用栈:

BackStackRecord: commit -> commitInternal
    FragmentManager: enqueueAction -> scheduleCommit
        HostCallBacks: getHandler.post

BackStackRecord

androidx.fragment.app.BackStackRecord#commit

1
2
3
4
public int commit() {
    // 参数为: boolean allowStateLoss
    return commitInternal(false);
}
enqueueAction

androidx.fragment.app.BackStackRecord#commitInternal

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
int commitInternal(boolean allowStateLoss) {
    if (mCommitted) throw new IllegalStateException("commit already called");
    mCommitted = true;
    // 如果在 commit 调用之前调用了 FragmentTransaction 的 addToBackStack, mAddToBackStack 就是 true, 否则 false
    if (mAddToBackStack) {
        mIndex = mManager.allocBackStackIndex();
    } else {
        mIndex = -1;
    }
    // FragmentManager#enququeAction
    // 第一个参数是 OpGenerator 类型
    mManager.enqueueAction(this, allowStateLoss);
    return mIndex;
}

BackStackRecord 实现了 OpGenrator 接口:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 实现了 OpGenrator 接口的 generateOps 方法
public boolean generateOps(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop) {
    // 将自己添加到 records 数组中
    records.add(this);
    isRecordPop.add(false);
    // 如果调用了 addToBackStack(), mAddToBackStack 就为 true
    if (mAddToBackStack) {
        // 将自己添加到 FragmentManager 的 mBackStack 数组中
        mManager.addBackStackState(this);
    }
    return true;
}

FragmentManager

androidx.fragment.app.FragmentManager#enqueueAction

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
void enqueueAction(OpGenerator action, boolean allowStateLoss) {
    //...
    synchronized (mPendingActions) {
        //...
        // 添加到等待队列中
        // mPendingActions: ArrayList<OpGenerator>
        mPendingActions.add(action);
        scheduleCommit();
    }
}

androidx.fragment.app.FragmentManager#scheduleCommit

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
void scheduleCommit() {
    synchronized (mPendingActions) {
        boolean postponeReady = mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
        // 一次只能提交一个 OpGenerator(BackStackRecord), 上面在 commit 里会通过 mCommitted 标志做过滤
        boolean pendingReady = mPendingActions.size() == 1;
        if (postponeReady || pendingReady) {
            // mExecCommit: Runnable
            // 通过 Handler 向主线程 Looper 中发消息. 当消息被消费时, 会执行 mExecCommit
            mHost.getHandler().removeCallbacks(mExecCommit);
            mHost.getHandler().post(mExecCommit);
            updateOnBackPressedCallbackEnabled();
        }
    }
}

commit 调用之后, mExecCommit 这个 Runnable 就作为一个 Message 的 callback 插入到主线程 MessageQueue 中, 之后 mExecCommit 会从消息池中取出, 然后执行:

mExecCommit 被执行

1
2
3
4
5
6
private Runnable mExecCommit = new Runnable() {
    @Override
    public void run() {
        execPendingActions(true);
    }
};
execPendingActions
 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
boolean execPendingActions(boolean allowStateLoss) {
    ensureExecReady(allowStateLoss);

    boolean didSomething = false;
    // 生成待处理操作
    while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
        mExecutingActions = true;
        try {
            // 删除冗余操作并执行
            removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
        } finally {
            cleanupExec();
        }
        didSomething = true;
    }

    updateOnBackPressedCallbackEnabled();
    doPendingDeferredStart();
    burpActive();

    return didSomething;
}

private void cleanupExec() {
    mExecutingActions = false;
    mTmpIsPop.clear();
    mTmpRecords.clear();
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
private boolean generateOpsForPendingActions(ArrayList<BackStackRecord> records, ArrayList<Boolean> isPop) {
    boolean didSomething = false;
    synchronized (mPendingActions) {
        if (mPendingActions.isEmpty()) {
            return false;
        }

        final int numActions = mPendingActions.size();
        for (int i = 0; i < numActions; i++) {
            // 将 mPendingActions 中的 actions, 通过调用 BackStackRecord 的 generateOps, 依次转移到 records
            didSomething |= mPendingActions.get(i).generateOps(records, isPop);
        }
        // 转移完成之后, 清空 mPendingActions
        mPendingActions.clear();
        // 执行完成之后, 移除 handler 中的回调
        mHost.getHandler().removeCallbacks(mExecCommit);
    }
    return didSomething;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
private void removeRedundantOperationsAndExecute(ArrayList<BackStackRecord> records,
        ArrayList<Boolean> isRecordPop) {
    //...
    // Force start of any postponed transactions that interact with scheduled transactions:
    executePostponedTransaction(records, isRecordPop);

    final int numRecords = records.size();
    int startIndex = 0;
    for (int recordNum = 0; recordNum < numRecords; recordNum++) {
        // mReorderingAllowed: 可以通过 FragmentTransaction 的 setReorderingAllowed 设置为 ture
        final boolean canReorder = records.get(recordNum).mReorderingAllowed;
        // 默认 false
        if (!canReorder) {
            // ...
            executeOpsTogether(records, isRecordPop, recordNum, reorderingEnd);
            startIndex = reorderingEnd;
            recordNum = reorderingEnd - 1;
        }
    }
    // ...
}
1
2
3
4
5
6
 private void executeOpsTogether(ArrayList<BackStackRecord> records,
        ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
    // ...
    executeOps(records, isRecordPop, startIndex, endIndex);
    // ...
}
executeOps
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
private static void executeOps(ArrayList<BackStackRecord> records,
        ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
    for (int i = startIndex; i < endIndex; i++) {
        final BackStackRecord record = records.get(i);
        final boolean isPop = isRecordPop.get(i);
        // 这里是 add 操作, isPop 为 false
        if (isPop) {
            record.bumpBackStackNesting(-1);
            boolean moveToState = i == (endIndex - 1);
            record.executePopOps(moveToState);
        } else {
            // BackStackRecord#bumpBackStackNesting
            record.bumpBackStackNesting(1);
            // BackStackRecord#executeOps
            record.executeOps();
        }
    }
}

回到 BackStackRecord:

androidx.fragment.app.BackStackRecord#executeOps

 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
void executeOps() {
    final int numOps = mOps.size();
    for (int opNum = 0; opNum < numOps; opNum++) {
        final Op op = mOps.get(opNum);
        final Fragment f = op.fragment;
        if (f != null) {
            f.setNextTransition(mTransition, mTransitionStyle);
        }
        // 执行不同命令
        switch (op.cmd) {
            case OP_ADD:
                f.setNextAnim(op.enterAnim);
                mManager.addFragment(f, false);
                break;
            case OP_REMOVE:
            //...
            case OP_HIDE:
            //...
            case OP_SHOW:
            //...
            case OP_DETACH:
            //...
            case OP_ATTACH:
            //...
        }
    }
    if (!mReorderingAllowed) {
        // 将 Fragment 切到当前状态
        mManager.moveToState(mManager.mCurState, true);
    }
}
addFragment
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
public void addFragment(Fragment fragment, boolean moveToStateNow) {
    if (DEBUG) Log.v(TAG, "add: " + fragment);
    makeActive(fragment);
    if (!fragment.mDetached) {
        // 不能重复添加同一个 Fragment
        if (mAdded.contains(fragment)) {
            throw new IllegalStateException("Fragment already added: " + fragment);
        }
        synchronized (mAdded) {
            // Fragment 添加到 mAdded 数组中
            mAdded.add(fragment);
        }
        fragment.mAdded = true;
        fragment.mRemoving = false;
        if (fragment.mView == null) {
            fragment.mHiddenChanged = false;
        }
        if (moveToStateNow) {
            moveToState(fragment);
        }
    }
}
makeActive
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
void makeActive(Fragment f) {
    // Fragment 的 mIndex 变量初始值为 -1
    if (f.mIndex >= 0) {
        return;
    }
    f.setIndex(mNextFragmentIndex++, mParent);
    if (mActive == null) {
        mActive = new SparseArray<>();
    }
    // Fragment 添加到 mActive Map 中
    mActive.put(f.mIndex, f);
}
moveToState
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
void moveToState(int newState, boolean always) {
    //...
    mCurState = newState;
    if (mActive != null) {
        final int numAdded = mAdded.size();
        for (int i = 0; i < numAdded; i++) {
            Fragment f = mAdded.get(i);
            moveFragmentToExpectedState(f);
        }
        //...
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
void moveFragmentToExpectedState(Fragment f) {
    if (f == null) {
        return;
    }
    int nextState = mCurState;
    // addFragment 时, f.mRemoving 赋值为 false
    if (f.mRemoving) {
        if (f.isInBackStack()) {
            nextState = Math.min(nextState, Fragment.CREATED);
        } else {
            nextState = Math.min(nextState, Fragment.INITIALIZING);
        }
    }
    // 真正开始切换状态
    moveToState(f, nextState, f.getNextTransition(), f.getNextTransitionStyle(), false);
    //...
}

moveState 方法有300行代码 🤦‍♂️

  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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
    void moveToState(Fragment f, int newState, int transit, int transitionStyle,
            boolean keepActive) {
        // Fragments that are not currently added will sit in the onCreate() state.
        if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
            newState = Fragment.CREATED;
        }
        if (f.mRemoving && newState > f.mState) {
            if (f.mState == Fragment.INITIALIZING && f.isInBackStack()) {
                // Allow the fragment to be created so that it can be saved later.
                newState = Fragment.CREATED;
            } else {
                // While removing a fragment, we can't change it to a higher state.
                newState = f.mState;
            }
        }
        // Defer start if requested; don't allow it to move to STARTED or higher
        // if it's not already started.
        if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.ACTIVITY_CREATED) {
            newState = Fragment.ACTIVITY_CREATED;
        }
        if (f.mState <= newState) {
            // For fragments that are created from a layout, when restoring from
            // state we don't want to allow them to be created until they are
            // being reloaded from the layout.
            if (f.mFromLayout && !f.mInLayout) {
                return;
            }
            if (f.getAnimatingAway() != null || f.getAnimator() != null) {
                // The fragment is currently being animated...  but!  Now we
                // want to move our state back up.  Give up on waiting for the
                // animation, move to whatever the final state should be once
                // the animation is done, and then we can proceed from there.
                f.setAnimatingAway(null);
                f.setAnimator(null);
                moveToState(f, f.getStateAfterAnimating(), 0, 0, true);
            }
            switch (f.mState) {
                case Fragment.INITIALIZING:
                    if (newState > Fragment.INITIALIZING) {
                        if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
                        if (f.mSavedFragmentState != null) {
                            f.mSavedFragmentState.setClassLoader(mHost.getContext()
                                    .getClassLoader());
                            f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
                                    FragmentManagerImpl.VIEW_STATE_TAG);
                            f.mTarget = getFragment(f.mSavedFragmentState,
                                    FragmentManagerImpl.TARGET_STATE_TAG);
                            if (f.mTarget != null) {
                                f.mTargetRequestCode = f.mSavedFragmentState.getInt(
                                        FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
                            }
                            if (f.mSavedUserVisibleHint != null) {
                                f.mUserVisibleHint = f.mSavedUserVisibleHint;
                                f.mSavedUserVisibleHint = null;
                            } else {
                                f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
                                        FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
                            }
                            if (!f.mUserVisibleHint) {
                                f.mDeferStart = true;
                                if (newState > Fragment.ACTIVITY_CREATED) {
                                    newState = Fragment.ACTIVITY_CREATED;
                                }
                            }
                        }

                        f.mHost = mHost;
                        f.mParentFragment = mParent;
                        f.mFragmentManager = mParent != null
                                ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();

                        // If we have a target fragment, push it along to at least CREATED
                        // so that this one can rely on it as an initialized dependency.
                        if (f.mTarget != null) {
                            if (mActive.get(f.mTarget.mIndex) != f.mTarget) {
                                throw new IllegalStateException("Fragment " + f
                                        + " declared target fragment " + f.mTarget
                                        + " that does not belong to this FragmentManager!");
                            }
                            if (f.mTarget.mState < Fragment.CREATED) {
                                moveToState(f.mTarget, Fragment.CREATED, 0, 0, true);
                            }
                        }

                        dispatchOnFragmentPreAttached(f, mHost.getContext(), false);
                        f.mCalled = false;
                        f.onAttach(mHost.getContext());
                        if (!f.mCalled) {
                            throw new SuperNotCalledException("Fragment " + f
                                    + " did not call through to super.onAttach()");
                        }
                        if (f.mParentFragment == null) {
                            mHost.onAttachFragment(f);
                        } else {
                            f.mParentFragment.onAttachFragment(f);
                        }
                        dispatchOnFragmentAttached(f, mHost.getContext(), false);

                        if (!f.mIsCreated) {
                            dispatchOnFragmentPreCreated(f, f.mSavedFragmentState, false);
                            f.performCreate(f.mSavedFragmentState);
                            dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
                        } else {
                            f.restoreChildFragmentState(f.mSavedFragmentState);
                            f.mState = Fragment.CREATED;
                        }
                        f.mRetaining = false;
                    }
                    // fall through
                case Fragment.CREATED:
                    // This is outside the if statement below on purpose; we want this to run
                    // even if we do a moveToState from CREATED => *, CREATED => CREATED, and
                    // * => CREATED as part of the case fallthrough above.
                    ensureInflatedFragmentView(f);

                    if (newState > Fragment.CREATED) {
                        if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
                        if (!f.mFromLayout) {
                            ViewGroup container = null;
                            if (f.mContainerId != 0) {
                                if (f.mContainerId == View.NO_ID) {
                                    throwException(new IllegalArgumentException(
                                            "Cannot create fragment "
                                                    + f
                                                    + " for a container view with no id"));
                                }
                                container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
                                if (container == null && !f.mRestored) {
                                    String resName;
                                    try {
                                        resName = f.getResources().getResourceName(f.mContainerId);
                                    } catch (NotFoundException e) {
                                        resName = "unknown";
                                    }
                                    throwException(new IllegalArgumentException(
                                            "No view found for id 0x"
                                            + Integer.toHexString(f.mContainerId) + " ("
                                            + resName
                                            + ") for fragment " + f));
                                }
                            }
                            f.mContainer = container;
                            f.performCreateView(f.performGetLayoutInflater(
                                    f.mSavedFragmentState), container, f.mSavedFragmentState);
                            if (f.mView != null) {
                                f.mInnerView = f.mView;
                                f.mView.setSaveFromParentEnabled(false);
                                if (container != null) {
                                    container.addView(f.mView);
                                }
                                if (f.mHidden) {
                                    f.mView.setVisibility(View.GONE);
                                }
                                f.onViewCreated(f.mView, f.mSavedFragmentState);
                                dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState,
                                        false);
                                // Only animate the view if it is visible. This is done after
                                // dispatchOnFragmentViewCreated in case visibility is changed
                                f.mIsNewlyAdded = (f.mView.getVisibility() == View.VISIBLE)
                                        && f.mContainer != null;
                            } else {
                                f.mInnerView = null;
                            }
                        }

                        f.performActivityCreated(f.mSavedFragmentState);
                        dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);
                        if (f.mView != null) {
                            f.restoreViewState(f.mSavedFragmentState);
                        }
                        f.mSavedFragmentState = null;
                    }
                    // fall through
                case Fragment.ACTIVITY_CREATED:
                    if (newState > Fragment.ACTIVITY_CREATED) {
                        if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
                        f.performStart();
                        dispatchOnFragmentStarted(f, false);
                    }
                    // fall through
                case Fragment.STARTED:
                    if (newState > Fragment.STARTED) {
                        if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
                        f.performResume();
                        dispatchOnFragmentResumed(f, false);
                        f.mSavedFragmentState = null;
                        f.mSavedViewState = null;
                    }
            }
        } else if (f.mState > newState) {
            switch (f.mState) {
                case Fragment.RESUMED:
                    if (newState < Fragment.RESUMED) {
                        if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
                        f.performPause();
                        dispatchOnFragmentPaused(f, false);
                    }
                    // fall through
                case Fragment.STARTED:
                    if (newState < Fragment.STARTED) {
                        if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
                        f.performStop();
                        dispatchOnFragmentStopped(f, false);
                    }
                    // fall through
                case Fragment.ACTIVITY_CREATED:
                    if (newState < Fragment.ACTIVITY_CREATED) {
                        if (DEBUG) Log.v(TAG, "movefrom ACTIVITY_CREATED: " + f);
                        if (f.mView != null) {
                            // Need to save the current view state if not
                            // done already.
                            if (mHost.onShouldSaveFragmentState(f) && f.mSavedViewState == null) {
                                saveFragmentViewState(f);
                            }
                        }
                        f.performDestroyView();
                        dispatchOnFragmentViewDestroyed(f, false);
                        if (f.mView != null && f.mContainer != null) {
                            // Stop any current animations:
                            f.mContainer.endViewTransition(f.mView);
                            f.mView.clearAnimation();
                            AnimationOrAnimator anim = null;
                            if (mCurState > Fragment.INITIALIZING && !mDestroyed
                                    && f.mView.getVisibility() == View.VISIBLE
                                    && f.mPostponedAlpha >= 0) {
                                anim = loadAnimation(f, transit, false,
                                        transitionStyle);
                            }
                            f.mPostponedAlpha = 0;
                            if (anim != null) {
                                animateRemoveFragment(f, anim, newState);
                            }
                            f.mContainer.removeView(f.mView);
                        }
                        f.mContainer = null;
                        f.mView = null;
                        // Set here to ensure that Observers are called after
                        // the Fragment's view is set to null
                        f.mViewLifecycleOwner = null;
                        f.mViewLifecycleOwnerLiveData.setValue(null);
                        f.mInnerView = null;
                        f.mInLayout = false;
                    }
                    // fall through
                case Fragment.CREATED:
                    if (newState < Fragment.CREATED) {
                        if (mDestroyed) {
                            // The fragment's containing activity is
                            // being destroyed, but this fragment is
                            // currently animating away.  Stop the
                            // animation right now -- it is not needed,
                            // and we can't wait any more on destroying
                            // the fragment.
                            if (f.getAnimatingAway() != null) {
                                View v = f.getAnimatingAway();
                                f.setAnimatingAway(null);
                                v.clearAnimation();
                            } else if (f.getAnimator() != null) {
                                Animator animator = f.getAnimator();
                                f.setAnimator(null);
                                animator.cancel();
                            }
                        }
                        if (f.getAnimatingAway() != null || f.getAnimator() != null) {
                            // We are waiting for the fragment's view to finish
                            // animating away.  Just make a note of the state
                            // the fragment now should move to once the animation
                            // is done.
                            f.setStateAfterAnimating(newState);
                            newState = Fragment.CREATED;
                        } else {
                            if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
                            if (!f.mRetaining) {
                                f.performDestroy();
                                dispatchOnFragmentDestroyed(f, false);
                            } else {
                                f.mState = Fragment.INITIALIZING;
                            }

                            f.performDetach();
                            dispatchOnFragmentDetached(f, false);
                            if (!keepActive) {
                                if (!f.mRetaining) {
                                    makeInactive(f);
                                } else {
                                    f.mHost = null;
                                    f.mParentFragment = null;
                                    f.mFragmentManager = null;
                                }
                            }
                        }
                    }
            }
        }

        if (f.mState != newState) {
            Log.w(TAG, "moveToState: Fragment state for " + f + " not updated inline; "
                    + "expected state " + newState + " found " + f.mState);
            f.mState = newState;
        }
    }
Support the author with
alipay QR Code
wechat QR Code

Yang
WRITTEN BY
Yang
Developer