Fragment来龙去脉

866 阅读5分钟

本文章来详细的跟踪一下关于fragment的相关的API和源码分析。

我们可以带着几个疑问来看fragment

  1. fragment是如何与activity进行关联的
  2. fragment生命周期与activity的生命周期的同步
  3. fragment是如何加入进去的

我们通常会在activity中这样来添加fragment

supportFragmentManager.beginTransaction().add(R.id.fragment_container, fragment).commit()

fragment涉及到几个核心的类:

FragmentManager 实现类是 FragmentManagerImpl
FragmentTransaction 实现类是 BackStackRecord

一、Activity是如何跟Fragment进行关联的

在FragmentActivity类中有一个成员变量

FragmentActivity.java

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

里面包含了两个类:FragmentController、HostCallbacks

1、FragmentController

这个类的主要作用是存储了mHosts对象,以及对生命周期变化时的分发。

FragmentController.java

private final FragmentHostCallback<?> mHost;
@NonNull
public static FragmentController createController(@NonNull FragmentHostCallback<?> callbacks) {
    return new FragmentController(checkNotNull(callbacks, "callbacks == null"));
}
public void attachHost(@Nullable Fragment parent) {
    mHost.mFragmentManager.attachController(
            mHost, mHost /*container*/, parent);
}
public void dispatchCreate() {
    mHost.mFragmentManager.dispatchCreate();
}
public void dispatchActivityCreated() {
    mHost.mFragmentManager.dispatchActivityCreated();
}
public void dispatchStart() {
    mHost.mFragmentManager.dispatchStart();
}
public void dispatchResume() {
    mHost.mFragmentManager.dispatchResume();
}

通过代码可以看出,这个类没有实际的实现代码,将所有的方法都分发给了mHost.mFragmentManager 那继续分析mHost是什么意思

2、HostCallbacks

HostCallbacks 是FragmentActivity的内部类 而这个类继承自FragmentHostCallback

FragmentActivity.java

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

继续看FragmentHostCallback干啥的 第一眼望去,就看到了它

FragmentHostCallback.java

final FragmentManager mFragmentManager = new FragmentManagerImpl();

3、那基本上就可以梳理一下了。

1.FragmentActivity 内部有一个成员变量mFragments 是FragmentController对象

2.FragmentController 内部包含一个成员变量mHost,和生命周期相关的方法。都是由mHost来分发的。是FragmentHostCallback对象

3.FragmentHostCallback 内部有一个成员变量mFragmentManager 是FragmentManager对象。

所以最终的具体实现还是回到了FragmentManager上面。

一个Activity 只能有一个FragmentManager

那我们知道了FragmentManager在FragmentActivity创建时创建的。那Activity又是什么时候创建的呢?

二、Fragment的生命周期

这就涉及到了Activity的创建流程,这里简单进行跟踪,主要是分析Fragment的生命周期与Activity的同步。

这里先引入一张图,来说明Activity、FragmentManager、Fragment三个之间的生命周期的关系

screenshot-20220415-164413.png

接着从Activity的创建流程出发来分析。

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { 
    ... 
    activity = mInstrumentation.newActivity(cl, component.getClassName(),r.intent);
    ... 
}

在newActivity()方法内部会创建 activity对象, 此时 FragmentManager 对象也会被创建。

1.attach()

接着看attach()方法的调用,也是在performLaunchActivity方法里面

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { 
    ... 
    activity = mInstrumentation.newActivity(cl, component.getClassName(),r.intent); 
    ... 
    activity.attach(...)
    ... 
}

在activity创建后,紧接着调用了attach()方法

final void attach() { 
    .... 
    mFragments.attachHost(null /*parent*/);
    ... 
}

这里终于看到了fragment相关的代码了。上面我们知道,mFragment是FragmentActivity创建的时候所创建的全局变量

而attachHost()方法也最后到了这里

public void attachHost(@Nullable Fragment parent) {
    mHost.mFragmentManager.attachController(
            mHost, mHost /*container*/, parent);
}
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;
    ....
}

其实可以看到,没有做实际的工作,就是初始化的操作。

2.onCreate()

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { 
    ... 
    activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent); 
    ... 
    activity.attach(...)
    ... 
    if (r.isPersistable()) {
        mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); 
    } else { 
        mInstrumentation.callActivityOnCreate(activity, r.state); 
    } 
}

继续看callActivityOnCreate方法

public void callActivityOnCreate(Activity activity, Bundle icicle, PersistableBundle persistentState) { 
    prePerformCreate(activity); 
    activity.performCreate(icicle, persistentState);
    postPerformCreate(activity); 
}

具体看activity.performCreate(icicle, persistentState);

final void performCreate(Bundle icicle, PersistableBundle persistentState) {
    ... 
    if (persistentState != null) { 
        onCreate(icicle, persistentState); 
    } else { 
        onCreate(icicle); 
    } 
    ... 
    mFragments.dispatchActivityCreated(); 
    ... 
}

又看到fragment相关的代码了,但是别急,onCreate方法里也有。

mFragments.dispatchCreate();

也就是说在activity onCreate方法调用时,fragment调用了两个生命周期。 分别是

dispatchCreate()

dispatchActivityCreated()

接着继续分析这两个方法

void dispatchCreate() {
    mStateSaved = false;
    mStopped = false;
    dispatchStateChange(Fragment.CREATED);
}

void dispatchActivityCreated() {
    mStateSaved = false;
    mStopped = false;
    dispatchStateChange(Fragment.ACTIVITY_CREATED);
}

里面都调用了dispatchStateChange方法,而且还有Fragment的静态成员变量。 先看看Fragment的静态成员变量都有哪些

Fragment.java

static final int INITIALIZING = -1;    // Not yet attached.
static final int ATTACHED = 0;         // Attached to the host.
static final int CREATED = 1;          // Created.
static final int ACTIVITY_CREATED = 2; // Fully created, not started.
static final int STARTED = 3;          // Created and started, not resumed.
static final int RESUMED = 4;          // Created started and resumed.

一共是有5个,默认是-1 继续看dispagchStateChange方法

private void dispatchStateChange(int nextState) {
    try {
        mExecutingActions = true;
        mFragmentStore.dispatchStateChange(nextState);
        moveToState(nextState, false);
    } finally {
        mExecutingActions = false;
    }
    execPendingActions(true);
}

最主要还是看moveToState方法

void moveToState(int newState, boolean always) {
    ...
    mCurState = newState;
    ...
    for (Fragment f : mFragmentStore.getFragments()) {
        moveFragmentToExpectedState(f);
    }
}

由此分析出,只要做了两个关键动作,将状态赋值给mCurState,并且遍历fragments,做movestate操作 到最后最后,还是执行了这个方法,里面代码很多,主要就是将fragment的生命周期进行调用。

void moveToState(@NonNull Fragment f, int newState) {
    
}

三、Fragment是怎么加入进来的

要说怎么加入进来的,那就从我们通常添加操作的方法入手。

supportFragmentManager.beginTransaction().add(R.id.fragment_container, fragment).commit()

1.supportFragmentManager

跟进去看这个supportFragmentManager是什么东西

FragmentActivity.java
@NonNull
public FragmentManager getSupportFragmentManager() {
    return mFragments.getSupportFragmentManager();
}
FragmentController.java
@NonNull
public FragmentManager getSupportFragmentManager() {
    return mHost.mFragmentManager;
}

从前面的分析我们可以看到,supportFragmentManager其实就是fragmentManager

2、beginTransaction()

@NonNull
public FragmentTransaction beginTransaction() {
    return new BackStackRecord(this);
}

FragmentTransaction类是做啥用的呢?

1、定义了Op对象,用于保存fragment对象和layoutid

2、定义了mOps队列用于保存Op对象

3、提供了add、replace等方法

3、add(layoutId,fragment)

跟踪源代码

FragmentTransction.java
@NonNull
public FragmentTransaction add(@IdRes int containerViewId, @NonNull Fragment fragment) {
    doAddOp(containerViewId, fragment, null, OP_ADD);
    return this;
}
FragmentTransction.java
void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
    final Class<?> fragmentClass = fragment.getClass();
    final int modifiers = fragmentClass.getModifiers();
    if (fragmentClass.isAnonymousClass() || !Modifier.isPublic(modifiers)
            || (fragmentClass.isMemberClass() && !Modifier.isStatic(modifiers))) {
        throw new IllegalStateException("Fragment " + fragmentClass.getCanonicalName()
                + " must be a public static class to be  properly recreated from"
                + " instance state.");
    }
    //1.根据tag来创建
    if (tag != null) {
        if (fragment.mTag != null && !tag.equals(fragment.mTag)) {
            throw new IllegalStateException("Can't change tag of fragment "
                    + fragment + ": was " + fragment.mTag
                    + " now " + tag);
        }
        fragment.mTag = tag;
    }
    //2.将rootid传递进来
    if (containerViewId != 0) {
        if (containerViewId == View.NO_ID) {
            throw new IllegalArgumentException("Can't add fragment "
                    + fragment + " with tag " + tag + " to container view with no id");
        }
        if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
            throw new IllegalStateException("Can't change container ID of fragment "
                    + fragment + ": was " + fragment.mFragmentId
                    + " now " + containerViewId);
        }
        fragment.mContainerId = fragment.mFragmentId = containerViewId;
    }
    //3.添加
    addOp(new Op(opcmd, fragment));
}

Op 就是保存有fragment和一些动画的属性

FragmentTransction.java
static final class Op {
    int mCmd;
    Fragment mFragment;
    int mEnterAnim;
    int mExitAnim;
    int mPopEnterAnim;
    int mPopExitAnim;
    Lifecycle.State mOldMaxState;
    Lifecycle.State mCurrentMaxState;

    Op() {
    }

addOp 方法就是把fragment layoutId 等封装好的Op 加入到mOps队列中

FragmentTransction.java
void addOp(Op op) {
    mOps.add(op);
    op.mEnterAnim = mEnterAnim;
    op.mExitAnim = mExitAnim;
    op.mPopEnterAnim = mPopEnterAnim;
    op.mPopExitAnim = mPopExitAnim;
}

mOps就是一个List集合

FragmentTransction.java
ArrayList<Op> mOps = new ArrayList<>();

将fragment等信息保存到集合中之后,是在什么时候取出来的呢? 这个时候就到了commit()方法了。 继续跟踪

4、commit()

commit方法是FragemtnTrasation调用的,实现类是BackStackRecord.

FragmentTransction.java
public abstract int commit();
@Override
public int commit() {
    return commitInternal(false);
}
int commitInternal(boolean allowStateLoss) {
    if (mCommitted) throw new IllegalStateException("commit already called");
    if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
        Log.v(TAG, "Commit: " + this);
        LogWriter logw = new LogWriter(TAG);
        PrintWriter pw = new PrintWriter(logw);
        dump("  ", pw);
        pw.close();
    }
    mCommitted = true;
    if (mAddToBackStack) {
        mIndex = mManager.allocBackStackIndex();
    } else {
        mIndex = -1;
    }
    //1.最后调用到了FragmentManager类中
    mManager.enqueueAction(this, allowStateLoss);
    return mIndex;
}
void enqueueAction(@NonNull OpGenerator action, boolean allowStateLoss) {
    ////省略几行代码
    synchronized (mPendingActions) {
        if (mHost == null) {
            if (allowStateLoss) {
                // This FragmentManager isn't attached, so drop the entire transaction.
                return;
            }
            throw new IllegalStateException("Activity has been destroyed");
        }
        mPendingActions.add(action);
        scheduleCommit();
    }
}
void scheduleCommit() {
    synchronized (mPendingActions) {
        boolean postponeReady =
                mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
        boolean pendingReady = mPendingActions.size() == 1;
        if (postponeReady || pendingReady) {
            //1.由此可见,是抛到主线程做的具体的操作
            mHost.getHandler().removeCallbacks(mExecCommit);
            mHost.getHandler().post(mExecCommit);
            updateOnBackPressedCallbackEnabled();
        }
    }
}
private Runnable mExecCommit = new Runnable() {
    @Override
    public void run() {
        execPendingActions(true);
    }
};
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();
    mFragmentStore.burpActive();

    return didSomething;
}

最后走到了这里

FragmentManager.java
private void executeOpsTogether(@NonNull ArrayList<BackStackRecord> records,
        @NonNull ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
    ////省略几行代码
    executeOps(records, isRecordPop, startIndex, endIndex);
    ////省略几行代码
}

最后走到了BackStackRecord的executePop方法内

void executePopOps(boolean moveToState) {
    for (int opNum = mOps.size() - 1; opNum >= 0; opNum--) {
        final Op op = mOps.get(opNum);
        Fragment f = op.mFragment;
        if (f != null) {
            f.setNextTransition(FragmentManager.reverseTransit(mTransition));
        }
        switch (op.mCmd) {
            case OP_ADD:
                f.setNextAnim(op.mPopExitAnim);
                mManager.setExitAnimationOrder(f, true);
                mManager.removeFragment(f);
                break;
            case OP_REMOVE:
                f.setNextAnim(op.mPopEnterAnim);
                mManager.addFragment(f);
                break;
            case OP_HIDE:
                f.setNextAnim(op.mPopEnterAnim);
                mManager.showFragment(f);
                break;
            case OP_SHOW:
                f.setNextAnim(op.mPopExitAnim);
                mManager.setExitAnimationOrder(f, true);
                mManager.hideFragment(f);
                break;
            case OP_DETACH:
                f.setNextAnim(op.mPopEnterAnim);
                mManager.attachFragment(f);
                break;
            case OP_ATTACH:
                f.setNextAnim(op.mPopExitAnim);
                mManager.setExitAnimationOrder(f, true);
                mManager.detachFragment(f);
                break;
            case OP_SET_PRIMARY_NAV:
                mManager.setPrimaryNavigationFragment(null);
                break;
            case OP_UNSET_PRIMARY_NAV:
                mManager.setPrimaryNavigationFragment(f);
                break;
            case OP_SET_MAX_LIFECYCLE:
                mManager.setMaxLifecycle(f, op.mOldMaxState);
                break;
            default:
                throw new IllegalArgumentException("Unknown cmd: " + op.mCmd);
        }
        if (!mReorderingAllowed && op.mCmd != OP_REMOVE && f != null) {
            mManager.moveFragmentToExpectedState(f);
        }
    }
    if (!mReorderingAllowed && moveToState) {
        mManager.moveToState(mManager.mCurState, true);
    }
}

里面做了两个操作,1、添加或者移除fragment 2、moveToState